diff --git a/3.7.0/.buildinfo b/3.7.0/.buildinfo new file mode 100644 index 000000000..41782d14c --- /dev/null +++ b/3.7.0/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 7eec20c34fb490fd5c9a3e2084023c05 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/3.7.0/.doctrees/advanced_examples.doctree b/3.7.0/.doctrees/advanced_examples.doctree new file mode 100644 index 000000000..ff1259ffa Binary files /dev/null and b/3.7.0/.doctrees/advanced_examples.doctree differ diff --git a/3.7.0/.doctrees/api/aoi.doctree b/3.7.0/.doctrees/api/aoi.doctree new file mode 100644 index 000000000..7860c872e Binary files /dev/null and b/3.7.0/.doctrees/api/aoi.doctree differ diff --git a/3.7.0/.doctrees/api/crs/coordinate_operation.doctree b/3.7.0/.doctrees/api/crs/coordinate_operation.doctree new file mode 100644 index 000000000..555111435 Binary files /dev/null and b/3.7.0/.doctrees/api/crs/coordinate_operation.doctree differ diff --git a/3.7.0/.doctrees/api/crs/coordinate_system.doctree b/3.7.0/.doctrees/api/crs/coordinate_system.doctree new file mode 100644 index 000000000..6af60cad7 Binary files /dev/null and b/3.7.0/.doctrees/api/crs/coordinate_system.doctree differ diff --git a/3.7.0/.doctrees/api/crs/crs.doctree b/3.7.0/.doctrees/api/crs/crs.doctree new file mode 100644 index 000000000..17b4205a7 Binary files /dev/null and b/3.7.0/.doctrees/api/crs/crs.doctree differ diff --git a/3.7.0/.doctrees/api/crs/datum.doctree b/3.7.0/.doctrees/api/crs/datum.doctree new file mode 100644 index 000000000..29a45b485 Binary files /dev/null and b/3.7.0/.doctrees/api/crs/datum.doctree differ diff --git a/3.7.0/.doctrees/api/crs/enums.doctree b/3.7.0/.doctrees/api/crs/enums.doctree new file mode 100644 index 000000000..0b8f327a2 Binary files /dev/null and b/3.7.0/.doctrees/api/crs/enums.doctree differ diff --git a/3.7.0/.doctrees/api/crs/index.doctree b/3.7.0/.doctrees/api/crs/index.doctree new file mode 100644 index 000000000..87a1b70ac Binary files /dev/null and b/3.7.0/.doctrees/api/crs/index.doctree differ diff --git a/3.7.0/.doctrees/api/database.doctree b/3.7.0/.doctrees/api/database.doctree new file mode 100644 index 000000000..823d229cf Binary files /dev/null and b/3.7.0/.doctrees/api/database.doctree differ diff --git a/3.7.0/.doctrees/api/datadir.doctree b/3.7.0/.doctrees/api/datadir.doctree new file mode 100644 index 000000000..57c4e1e9f Binary files /dev/null and b/3.7.0/.doctrees/api/datadir.doctree differ diff --git a/3.7.0/.doctrees/api/enums.doctree b/3.7.0/.doctrees/api/enums.doctree new file mode 100644 index 000000000..caeb9012c Binary files /dev/null and b/3.7.0/.doctrees/api/enums.doctree differ diff --git a/3.7.0/.doctrees/api/exceptions.doctree b/3.7.0/.doctrees/api/exceptions.doctree new file mode 100644 index 000000000..775b2457d Binary files /dev/null and b/3.7.0/.doctrees/api/exceptions.doctree differ diff --git a/3.7.0/.doctrees/api/geod.doctree b/3.7.0/.doctrees/api/geod.doctree new file mode 100644 index 000000000..bb2b72a53 Binary files /dev/null and b/3.7.0/.doctrees/api/geod.doctree differ diff --git a/3.7.0/.doctrees/api/global_context.doctree b/3.7.0/.doctrees/api/global_context.doctree new file mode 100644 index 000000000..5cbb3c7ce Binary files /dev/null and b/3.7.0/.doctrees/api/global_context.doctree differ diff --git a/3.7.0/.doctrees/api/index.doctree b/3.7.0/.doctrees/api/index.doctree new file mode 100644 index 000000000..96dd44b33 Binary files /dev/null and b/3.7.0/.doctrees/api/index.doctree differ diff --git a/3.7.0/.doctrees/api/list.doctree b/3.7.0/.doctrees/api/list.doctree new file mode 100644 index 000000000..fae22caf3 Binary files /dev/null and b/3.7.0/.doctrees/api/list.doctree differ diff --git a/3.7.0/.doctrees/api/network.doctree b/3.7.0/.doctrees/api/network.doctree new file mode 100644 index 000000000..2b682dc0d Binary files /dev/null and b/3.7.0/.doctrees/api/network.doctree differ diff --git a/3.7.0/.doctrees/api/proj.doctree b/3.7.0/.doctrees/api/proj.doctree new file mode 100644 index 000000000..cfcf4ed57 Binary files /dev/null and b/3.7.0/.doctrees/api/proj.doctree differ diff --git a/3.7.0/.doctrees/api/show_versions.doctree b/3.7.0/.doctrees/api/show_versions.doctree new file mode 100644 index 000000000..e89f60d94 Binary files /dev/null and b/3.7.0/.doctrees/api/show_versions.doctree differ diff --git a/3.7.0/.doctrees/api/sync.doctree b/3.7.0/.doctrees/api/sync.doctree new file mode 100644 index 000000000..e0558f6b2 Binary files /dev/null and b/3.7.0/.doctrees/api/sync.doctree differ diff --git a/3.7.0/.doctrees/api/transformer.doctree b/3.7.0/.doctrees/api/transformer.doctree new file mode 100644 index 000000000..3fb964112 Binary files /dev/null and b/3.7.0/.doctrees/api/transformer.doctree differ diff --git a/3.7.0/.doctrees/build_crs.doctree b/3.7.0/.doctrees/build_crs.doctree new file mode 100644 index 000000000..e1c3f7199 Binary files /dev/null and b/3.7.0/.doctrees/build_crs.doctree differ diff --git a/3.7.0/.doctrees/build_crs_cf.doctree b/3.7.0/.doctrees/build_crs_cf.doctree new file mode 100644 index 000000000..ee669bf8a Binary files /dev/null and b/3.7.0/.doctrees/build_crs_cf.doctree differ diff --git a/3.7.0/.doctrees/cli.doctree b/3.7.0/.doctrees/cli.doctree new file mode 100644 index 000000000..605f3d98b Binary files /dev/null and b/3.7.0/.doctrees/cli.doctree differ diff --git a/3.7.0/.doctrees/crs_compatibility.doctree b/3.7.0/.doctrees/crs_compatibility.doctree new file mode 100644 index 000000000..20e8b2a26 Binary files /dev/null and b/3.7.0/.doctrees/crs_compatibility.doctree differ diff --git a/3.7.0/.doctrees/environment.pickle b/3.7.0/.doctrees/environment.pickle new file mode 100644 index 000000000..bb54952b9 Binary files /dev/null and b/3.7.0/.doctrees/environment.pickle differ diff --git a/3.7.0/.doctrees/examples.doctree b/3.7.0/.doctrees/examples.doctree new file mode 100644 index 000000000..96ee2d758 Binary files /dev/null and b/3.7.0/.doctrees/examples.doctree differ diff --git a/3.7.0/.doctrees/gotchas.doctree b/3.7.0/.doctrees/gotchas.doctree new file mode 100644 index 000000000..dc950ebc7 Binary files /dev/null and b/3.7.0/.doctrees/gotchas.doctree differ diff --git a/3.7.0/.doctrees/history.doctree b/3.7.0/.doctrees/history.doctree new file mode 100644 index 000000000..36efacaa3 Binary files /dev/null and b/3.7.0/.doctrees/history.doctree differ diff --git a/3.7.0/.doctrees/index.doctree b/3.7.0/.doctrees/index.doctree new file mode 100644 index 000000000..70a0089d5 Binary files /dev/null and b/3.7.0/.doctrees/index.doctree differ diff --git a/3.7.0/.doctrees/installation.doctree b/3.7.0/.doctrees/installation.doctree new file mode 100644 index 000000000..91673e586 Binary files /dev/null and b/3.7.0/.doctrees/installation.doctree differ diff --git a/3.7.0/.doctrees/optimize_transformations.doctree b/3.7.0/.doctrees/optimize_transformations.doctree new file mode 100644 index 000000000..b1718dbd5 Binary files /dev/null and b/3.7.0/.doctrees/optimize_transformations.doctree differ diff --git a/3.7.0/.doctrees/past_versions.doctree b/3.7.0/.doctrees/past_versions.doctree new file mode 100644 index 000000000..10d2b60f3 Binary files /dev/null and b/3.7.0/.doctrees/past_versions.doctree differ diff --git a/3.7.0/.doctrees/transformation_grids.doctree b/3.7.0/.doctrees/transformation_grids.doctree new file mode 100644 index 000000000..c8c4340f7 Binary files /dev/null and b/3.7.0/.doctrees/transformation_grids.doctree differ diff --git a/3.7.0/_modules/index.html b/3.7.0/_modules/index.html new file mode 100644 index 000000000..082f4228a --- /dev/null +++ b/3.7.0/_modules/index.html @@ -0,0 +1,334 @@ + + + + + + + + Overview: module code - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+ +
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/_show_versions.html b/3.7.0/_modules/pyproj/_show_versions.html new file mode 100644 index 000000000..da4a5edcb --- /dev/null +++ b/3.7.0/_modules/pyproj/_show_versions.html @@ -0,0 +1,435 @@ + + + + + + + + pyproj._show_versions - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj._show_versions

+"""
+Utility methods to print system info for debugging
+
+adapted from :func:`sklearn.utils._show_versions`
+which was adapted from :func:`pandas.show_versions`
+"""
+
+import importlib.metadata
+import platform
+import sys
+
+
+def _get_sys_info():
+    """System information
+    Return
+    ------
+    sys_info : dict
+        system and Python version information
+    """
+    blob = [
+        ("python", sys.version.replace("\n", " ")),
+        ("executable", sys.executable),
+        ("machine", platform.platform()),
+    ]
+
+    return dict(blob)
+
+
+def _get_proj_info():
+    """Information on system PROJ
+
+    Returns
+    -------
+    proj_info: dict
+        system PROJ information
+    """
+    # pylint: disable=import-outside-toplevel
+    import pyproj
+    from pyproj.database import get_database_metadata
+    from pyproj.exceptions import DataDirError
+
+    try:
+        data_dir = pyproj.datadir.get_data_dir()
+    except DataDirError:
+        data_dir = None
+
+    blob = [
+        ("pyproj", pyproj.__version__),
+        ("PROJ (runtime)", pyproj.__proj_version__),
+        ("PROJ (compiled)", pyproj.__proj_compiled_version__),
+        ("data dir", data_dir),
+        ("user_data_dir", pyproj.datadir.get_user_data_dir()),
+        ("PROJ DATA (recommended version)", get_database_metadata("PROJ_DATA.VERSION")),
+        (
+            "PROJ Database",
+            f"{get_database_metadata('DATABASE.LAYOUT.VERSION.MAJOR')}."
+            f"{get_database_metadata('DATABASE.LAYOUT.VERSION.MINOR')}",
+        ),
+        (
+            "EPSG Database",
+            f"{get_database_metadata('EPSG.VERSION')} "
+            f"[{get_database_metadata('EPSG.DATE')}]",
+        ),
+        (
+            "ESRI Database",
+            f"{get_database_metadata('ESRI.VERSION')} "
+            f"[{get_database_metadata('ESRI.DATE')}]",
+        ),
+        (
+            "IGNF Database",
+            f"{get_database_metadata('IGNF.VERSION')} "
+            f"[{get_database_metadata('IGNF.DATE')}]",
+        ),
+    ]
+
+    return dict(blob)
+
+
+def _get_deps_info():
+    """Overview of the installed version of main dependencies
+    Returns
+    -------
+    deps_info: dict
+        version information on relevant Python libraries
+    """
+    deps = ["certifi", "Cython", "setuptools", "pip"]
+
+    def get_version(module):
+        try:
+            return importlib.metadata.version(module)
+        except importlib.metadata.PackageNotFoundError:
+            return None
+
+    return {dep: get_version(dep) for dep in deps}
+
+
+def _print_info_dict(info_dict):
+    """Print the information dictionary"""
+    for key, stat in info_dict.items():
+        print(f"{key:>10}: {stat}")
+
+
+
+[docs] +def show_versions(): + """ + .. versionadded:: 2.2.1 + + Print useful debugging information + + Example + ------- + > python -c "import pyproj; pyproj.show_versions()" + + """ + print("pyproj info:") + _print_info_dict(_get_proj_info()) + print("\nSystem:") + _print_info_dict(_get_sys_info()) + print("\nPython deps:") + _print_info_dict(_get_deps_info())
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/aoi.html b/3.7.0/_modules/pyproj/aoi.html new file mode 100644 index 000000000..5eafe8e6f --- /dev/null +++ b/3.7.0/_modules/pyproj/aoi.html @@ -0,0 +1,467 @@ + + + + + + + + pyproj.aoi - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.aoi

+"""
+This module contains the structures related to areas of interest.
+"""
+
+from dataclasses import dataclass
+from typing import NamedTuple, Union
+
+from pyproj.utils import is_null
+
+
+
+[docs] +@dataclass(frozen=True) +class AreaOfInterest: + """ + .. versionadded:: 2.3.0 + + This is the area of interest for: + + - Transformations + - Querying for CRS data. + """ + + #: The west bound in degrees of the area of interest. + west_lon_degree: float + #: The south bound in degrees of the area of interest. + south_lat_degree: float + #: The east bound in degrees of the area of interest. + east_lon_degree: float + #: The north bound in degrees of the area of interest. + north_lat_degree: float + + def __post_init__(self): + if ( + is_null(self.west_lon_degree) + or is_null(self.south_lat_degree) + or is_null(self.east_lon_degree) + or is_null(self.north_lat_degree) + ): + raise ValueError("NaN or None values are not allowed.")
+ + + +
+[docs] +class AreaOfUse(NamedTuple): + """ + .. versionadded:: 2.0.0 + + Area of Use for CRS, CoordinateOperation, or a Transformer. + """ + + #: West bound of area of use. + west: float + #: South bound of area of use. + south: float + #: East bound of area of use. + east: float + #: North bound of area of use. + north: float + #: Name of area of use. + name: str | None = None + + @property + def bounds(self) -> tuple[float, float, float, float]: + """ + The bounds of the area of use. + + Returns + ------- + tuple[float, float, float, float] + west, south, east, and north bounds. + """ + return self.west, self.south, self.east, self.north + + def __str__(self) -> str: + return f"- name: {self.name}\n" f"- bounds: {self.bounds}"
+ + + +
+[docs] +@dataclass +class BBox: + """ + Bounding box to check if data intersects/contains other + bounding boxes. + + .. versionadded:: 3.0.0 + + """ + + #: West bound of bounding box. + west: float + #: South bound of bounding box. + south: float + #: East bound of bounding box. + east: float + #: North bound of bounding box. + north: float + + def __post_init__(self): + if ( + is_null(self.west) + or is_null(self.south) + or is_null(self.east) + or is_null(self.north) + ): + raise ValueError("NaN or None values are not allowed.") + +
+[docs] + def intersects(self, other: Union["BBox", AreaOfUse]) -> bool: + """ + Parameters + ---------- + other: BBox + The other BBox to use to check. + + Returns + ------- + bool: + True if this BBox intersects the other bbox. + """ + return ( + self.west < other.east + and other.west < self.east + and self.south < other.north + and other.south < self.north + )
+ + +
+[docs] + def contains(self, other: Union["BBox", AreaOfUse]) -> bool: + """ + Parameters + ---------- + other: Union["BBox", AreaOfUse] + The other BBox to use to check. + + Returns + ------- + bool: + True if this BBox contains the other bbox. + """ + return ( + other.west >= self.west + and other.east <= self.east + and other.south >= self.south + and other.north <= self.north + )
+
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/crs/coordinate_operation.html b/3.7.0/_modules/pyproj/crs/coordinate_operation.html new file mode 100644 index 000000000..7c99bf61a --- /dev/null +++ b/3.7.0/_modules/pyproj/crs/coordinate_operation.html @@ -0,0 +1,2186 @@ + + + + + + + + pyproj.crs.coordinate_operation - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.crs.coordinate_operation

+"""
+This module is for building operations to be used when
+building a CRS.
+
+:ref:`operations`
+"""
+
+# pylint: disable=too-many-lines
+import warnings
+from typing import Any, Optional
+
+from pyproj._crs import CoordinateOperation
+from pyproj._version import PROJ_VERSION
+from pyproj.exceptions import CRSError
+
+
+
+[docs] +class AlbersEqualAreaConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Albers Equal Area Conversion. + + :ref:`PROJ docs <aea>` + """ + +
+[docs] + def __new__( + cls, + latitude_first_parallel: float, + latitude_second_parallel: float, + latitude_false_origin: float = 0.0, + longitude_false_origin: float = 0.0, + easting_false_origin: float = 0.0, + northing_false_origin: float = 0.0, + ): + """ + Parameters + ---------- + latitude_first_parallel: float + First standard parallel (lat_1). + latitude_second_parallel: float + Second standard parallel (lat_2). + latitude_false_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_false_origin: float, default=0.0 + Longitude of projection center (lon_0). + easting_false_origin: float, default=0.0 + False easting (x_0). + northing_false_origin: float, default=0.0 + False northing (y_0). + """ + aea_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Albers Equal Area", + "id": {"authority": "EPSG", "code": 9822}, + }, + "parameters": [ + { + "name": "Latitude of false origin", + "value": latitude_false_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8821}, + }, + { + "name": "Longitude of false origin", + "value": longitude_false_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8822}, + }, + { + "name": "Latitude of 1st standard parallel", + "value": latitude_first_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8823}, + }, + { + "name": "Latitude of 2nd standard parallel", + "value": latitude_second_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8824}, + }, + { + "name": "Easting at false origin", + "value": easting_false_origin, + "unit": { + "type": "LinearUnit", + "name": "Metre", + "conversion_factor": 1, + }, + "id": {"authority": "EPSG", "code": 8826}, + }, + { + "name": "Northing at false origin", + "value": northing_false_origin, + "unit": { + "type": "LinearUnit", + "name": "Metre", + "conversion_factor": 1, + }, + "id": {"authority": "EPSG", "code": 8827}, + }, + ], + } + return cls.from_json_dict(aea_json)
+
+ + + +
+[docs] +class AzimuthalEquidistantConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 AzumuthalEquidistantConversion + .. versionadded:: 3.2.0 AzimuthalEquidistantConversion + + Class for constructing the Modified Azimuthal Equidistant conversion. + + :ref:`PROJ docs <aeqd>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + aeqd_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Modified Azimuthal Equidistant", + "id": {"authority": "EPSG", "code": 9832}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(aeqd_json)
+
+ + + +
+[docs] +class GeostationarySatelliteConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Geostationary Satellite conversion. + + :ref:`PROJ docs <geos>` + """ + +
+[docs] + def __new__( + cls, + sweep_angle_axis: str, + satellite_height: float, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + sweep_angle_axis: str + Sweep angle axis of the viewing instrument. Valid options are “X” and “Y”. + satellite_height: float + Satellite height. + latitude_natural_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + sweep_angle_axis = sweep_angle_axis.strip().upper() + valid_sweep_axis = ("X", "Y") + if sweep_angle_axis not in valid_sweep_axis: + raise CRSError(f"sweep_angle_axis only supports {valid_sweep_axis}") + + if latitude_natural_origin != 0: + warnings.warn( + "The latitude of natural origin (lat_0) is not used " + "within PROJ. It is only supported for exporting to " + "the WKT or PROJ JSON formats." + ) + + geos_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": {"name": f"Geostationary Satellite (Sweep {sweep_angle_axis})"}, + "parameters": [ + { + "name": "Satellite height", + "value": satellite_height, + "unit": "metre", + }, + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(geos_json)
+
+ + + +
+[docs] +class LambertAzimuthalEqualAreaConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 LambertAzumuthalEqualAreaConversion + .. versionadded:: 3.2.0 LambertAzimuthalEqualAreaConversion + + Class for constructing the Lambert Azimuthal Equal Area conversion. + + :ref:`PROJ docs <laea>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + laea_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Lambert Azimuthal Equal Area", + "id": {"authority": "EPSG", "code": 9820}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(laea_json)
+
+ + + +
+[docs] +class LambertConformalConic2SPConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Lambert Conformal Conic 2SP conversion. + + :ref:`PROJ docs <lcc>` + """ + +
+[docs] + def __new__( + cls, + latitude_first_parallel: float, + latitude_second_parallel: float, + latitude_false_origin: float = 0.0, + longitude_false_origin: float = 0.0, + easting_false_origin: float = 0.0, + northing_false_origin: float = 0.0, + ): + """ + Parameters + ---------- + latitude_first_parallel: float + Latitude of 1st standard parallel (lat_1). + latitude_second_parallel: float + Latitude of 2nd standard parallel (lat_2). + latitude_false_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_false_origin: float, default=0.0 + Longitude of projection center (lon_0). + easting_false_origin: float, default=0.0 + False easting (x_0). + northing_false_origin: float, default=0.0 + False northing (y_0). + + """ + lcc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Lambert Conic Conformal (2SP)", + "id": {"authority": "EPSG", "code": 9802}, + }, + "parameters": [ + { + "name": "Latitude of 1st standard parallel", + "value": latitude_first_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8823}, + }, + { + "name": "Latitude of 2nd standard parallel", + "value": latitude_second_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8824}, + }, + { + "name": "Latitude of false origin", + "value": latitude_false_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8821}, + }, + { + "name": "Longitude of false origin", + "value": longitude_false_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8822}, + }, + { + "name": "Easting at false origin", + "value": easting_false_origin, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8826}, + }, + { + "name": "Northing at false origin", + "value": northing_false_origin, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8827}, + }, + ], + } + return cls.from_json_dict(lcc_json)
+
+ + + +
+[docs] +class LambertConformalConic1SPConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Lambert Conformal Conic 1SP conversion. + + :ref:`PROJ docs <lcc>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + scale_factor_natural_origin: float = 1.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + scale_factor_natural_origin: float, default=1.0 + Scale factor at natural origin (k_0). + + """ + lcc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Lambert Conic Conformal (1SP)", + "id": {"authority": "EPSG", "code": 9801}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "Scale factor at natural origin", + "value": scale_factor_natural_origin, + "unit": "unity", + "id": {"authority": "EPSG", "code": 8805}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(lcc_json)
+
+ + + +
+[docs] +class LambertCylindricalEqualAreaConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Lambert Cylindrical Equal Area conversion. + + :ref:`PROJ docs <cea>` + """ + +
+[docs] + def __new__( + cls, + latitude_first_parallel: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_first_parallel: float, default=0.0 + Latitude of 1st standard parallel (lat_ts). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + cea_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Lambert Cylindrical Equal Area", + "id": {"authority": "EPSG", "code": 9835}, + }, + "parameters": [ + { + "name": "Latitude of 1st standard parallel", + "value": latitude_first_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8823}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(cea_json)
+
+ + + +
+[docs] +class LambertCylindricalEqualAreaScaleConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Lambert Cylindrical Equal Area conversion. + + This version uses the scale factor and differs from the official version. + + The scale factor will be converted to the Latitude of 1st standard parallel (lat_ts) + when exporting to WKT in PROJ>=7.0.0. Previous version will export it as a + PROJ-based coordinate operation in the WKT. + + :ref:`PROJ docs <cea>` + """ + + def __new__( + cls, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + scale_factor_natural_origin: float = 1.0, + ): + """ + Parameters + ---------- + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + scale_factor_natural_origin: float, default=1.0 + Scale factor at natural origin (k or k_0). + + """ + # pylint: disable=import-outside-toplevel + from pyproj.crs import CRS + + # hack due to: https://github.com/OSGeo/PROJ/issues/1881 + proj_string = ( + "+proj=cea " + f"+lon_0={longitude_natural_origin} " + f"+x_0={false_easting} " + f"+y_0={false_northing} " + f"+k_0={scale_factor_natural_origin}" + ) + return cls.from_json( + CRS(proj_string).coordinate_operation.to_json() # type: ignore + )
+ + + +
+[docs] +class MercatorAConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Mercator (variant A) conversion. + + :ref:`PROJ docs <merc>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + scale_factor_natural_origin: float = 1.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of natural origin (lat_0). Must be 0 by `this conversion's + definition + <https://epsg.org/coord-operation-method_9804/Mercator-variant-A.html>`_. + longitude_natural_origin: float, default=0.0 + Longitude of natural origin (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + scale_factor_natural_origin: float, default=1.0 + Scale factor at natural origin (k or k_0). + + """ + if latitude_natural_origin != 0: + raise CRSError( + "This conversion is defined for only latitude_natural_origin = 0." + ) + merc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Mercator (variant A)", + "id": {"authority": "EPSG", "code": 9804}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "Scale factor at natural origin", + "value": scale_factor_natural_origin, + "unit": "unity", + "id": {"authority": "EPSG", "code": 8805}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(merc_json)
+
+ + + +
+[docs] +class MercatorBConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Mercator (variant B) conversion. + + :ref:`PROJ docs <merc>` + """ + +
+[docs] + def __new__( + cls, + latitude_first_parallel: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_first_parallel: float, default=0.0 + Latitude of 1st standard parallel (lat_ts). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + merc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Mercator (variant B)", + "id": {"authority": "EPSG", "code": 9805}, + }, + "parameters": [ + { + "name": "Latitude of 1st standard parallel", + "value": latitude_first_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8823}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(merc_json)
+
+ + + +
+[docs] +class HotineObliqueMercatorBConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + .. versionadded:: 3.7.0 azimuth_projection_centre, scale_factor_projection_centre + + Class for constructing the Hotine Oblique Mercator (variant B) conversion. + + :ref:`PROJ docs <omerc>` + """ + +
+[docs] + def __new__( + cls, + latitude_projection_centre: float, + longitude_projection_centre: float, + angle_from_rectified_to_skew_grid: float, + easting_projection_centre: float = 0.0, + northing_projection_centre: float = 0.0, + azimuth_projection_centre: Optional[float] = None, + scale_factor_projection_centre: Optional[float] = None, + azimuth_initial_line: Optional[float] = None, + scale_factor_on_initial_line: Optional[float] = None, + ): + """ + Parameters + ---------- + latitude_projection_centre: float + Latitude of projection centre (lat_0). + longitude_projection_centre: float + Longitude of projection centre (lonc). + azimuth_projection_centre: float + Azimuth of initial line (alpha). + angle_from_rectified_to_skew_grid: float + Angle from Rectified to Skew Grid (gamma). + scale_factor_projection_centre: float, default=1.0 + Scale factor on initial line (k or k_0). + easting_projection_centre: float, default=0.0 + Easting at projection centre (x_0). + northing_projection_centre: float, default=0.0 + Northing at projection centre (y_0). + azimuth_initial_line: float + Deprecated alias for azimuth_projection_centre, + scale_factor_on_initial_line: float + Deprecated alias for scale_factor_projection_centre. + """ + if scale_factor_on_initial_line is not None: + if scale_factor_projection_centre is not None: + raise ValueError( + "scale_factor_projection_centre and scale_factor_on_initial_line " + "cannot be provided together." + ) + warnings.warn( + "scale_factor_on_initial_line is deprecated. " + "Use scale_factor_projection_centre instead.", + FutureWarning, + stacklevel=2, + ) + scale_factor_projection_centre = scale_factor_on_initial_line + elif scale_factor_projection_centre is None: + scale_factor_projection_centre = 1.0 + + if azimuth_projection_centre is None and azimuth_initial_line is None: + raise ValueError( + "azimuth_projection_centre or azimuth_initial_line must be provided." + ) + if azimuth_initial_line is not None: + if azimuth_projection_centre is not None: + raise ValueError( + "azimuth_projection_centre and azimuth_initial_line cannot be " + "provided together." + ) + warnings.warn( + "azimuth_initial_line is deprecated. " + "Use azimuth_projection_centre instead.", + FutureWarning, + stacklevel=2, + ) + azimuth_projection_centre = azimuth_initial_line + + omerc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Hotine Oblique Mercator (variant B)", + "id": {"authority": "EPSG", "code": 9815}, + }, + "parameters": [ + { + "name": "Latitude of projection centre", + "value": latitude_projection_centre, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8811}, + }, + { + "name": "Longitude of projection centre", + "value": longitude_projection_centre, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8812}, + }, + { + "name": ( + "Azimuth at projection centre" + if PROJ_VERSION >= (9, 5, 0) + else "Azimuth of initial line" + ), + "value": azimuth_projection_centre, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8813}, + }, + { + "name": "Angle from Rectified to Skew Grid", + "value": angle_from_rectified_to_skew_grid, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8814}, + }, + { + "name": ( + "Scale factor at projection centre" + if PROJ_VERSION >= (9, 5, 0) + else "Scale factor on initial line" + ), + "value": scale_factor_projection_centre, + "unit": "unity", + "id": {"authority": "EPSG", "code": 8815}, + }, + { + "name": "Easting at projection centre", + "value": easting_projection_centre, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8816}, + }, + { + "name": "Northing at projection centre", + "value": northing_projection_centre, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8817}, + }, + ], + } + return cls.from_json_dict(omerc_json)
+
+ + + +
+[docs] +class OrthographicConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Orthographic conversion. + + :ref:`PROJ docs <ortho>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + ortho_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Orthographic", + "id": {"authority": "EPSG", "code": 9840}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(ortho_json)
+
+ + + +
+[docs] +class PolarStereographicAConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Polar Stereographic A conversion. + + :ref:`PROJ docs <stere>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + scale_factor_natural_origin: float = 1.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float + Latitude of natural origin (lat_0). Either +90 or -90. + longitude_natural_origin: float, default=0.0 + Longitude of natural origin (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + scale_factor_natural_origin: float, default=0.0 + Scale factor at natural origin (k or k_0). + + """ + + stere_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Polar Stereographic (variant A)", + "id": {"authority": "EPSG", "code": 9810}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "Scale factor at natural origin", + "value": scale_factor_natural_origin, + "unit": "unity", + "id": {"authority": "EPSG", "code": 8805}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(stere_json)
+
+ + + +
+[docs] +class PolarStereographicBConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Polar Stereographic B conversion. + + :ref:`PROJ docs <stere>` + """ + +
+[docs] + def __new__( + cls, + latitude_standard_parallel: float = 0.0, + longitude_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_standard_parallel: float, default=0.0 + Latitude of standard parallel (lat_ts). + longitude_origin: float, default=0.0 + Longitude of origin (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + stere_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Polar Stereographic (variant B)", + "id": {"authority": "EPSG", "code": 9829}, + }, + "parameters": [ + { + "name": "Latitude of standard parallel", + "value": latitude_standard_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8832}, + }, + { + "name": "Longitude of origin", + "value": longitude_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8833}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(stere_json)
+
+ + + +
+[docs] +class SinusoidalConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Sinusoidal conversion. + + :ref:`PROJ docs <sinu>` + """ + +
+[docs] + def __new__( + cls, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + sinu_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": {"name": "Sinusoidal"}, + "parameters": [ + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(sinu_json)
+
+ + + +
+[docs] +class StereographicConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Stereographic conversion. + + :ref:`PROJ docs <stere>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + scale_factor_natural_origin: float = 1.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of natural origin (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of natural origin (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + scale_factor_natural_origin: float, default=1.0 + Scale factor at natural origin (k or k_0). + + """ + + stere_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": {"name": "Stereographic"}, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "Scale factor at natural origin", + "value": scale_factor_natural_origin, + "unit": "unity", + "id": {"authority": "EPSG", "code": 8805}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(stere_json)
+
+ + + +
+[docs] +class UTMConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the UTM conversion. + + :ref:`PROJ docs <utm>` + """ + +
+[docs] + def __new__(cls, zone: str, hemisphere: str = "N"): + """ + Parameters + ---------- + zone: int + UTM Zone between 1-60. + hemisphere: str, default="N" + Either N for North or S for South. + """ + return cls.from_name(f"UTM zone {zone}{hemisphere}")
+
+ + + +
+[docs] +class TransverseMercatorConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Transverse Mercator conversion. + + :ref:`PROJ docs <tmerc>` + """ + +
+[docs] + def __new__( + cls, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + scale_factor_natural_origin: float = 1.0, + ): + """ + Parameters + ---------- + latitude_natural_origin: float, default=0.0 + Latitude of projection center (lat_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + scale_factor_natural_origin: float, default=1.0 + Scale factor at natural origin (k or k_0). + + """ + tmerc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Transverse Mercator", + "id": {"authority": "EPSG", "code": 9807}, + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "Scale factor at natural origin", + "value": scale_factor_natural_origin, + "unit": "unity", + "id": {"authority": "EPSG", "code": 8805}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(tmerc_json)
+
+ + + +
+[docs] +class VerticalPerspectiveConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Vertical Perspective conversion. + + :ref:`PROJ docs <nsper>` + """ + +
+[docs] + def __new__( + cls, + viewpoint_height: float, + latitude_topocentric_origin: float = 0.0, + longitude_topocentric_origin: float = 0.0, + ellipsoidal_height_topocentric_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + viewpoint_height: float + Viewpoint height (h). + latitude_topocentric_origin: float, default=0.0 + Latitude of topocentric origin (lat_0). + longitude_topocentric_origin: float, default=0.0 + Longitude of topocentric origin (lon_0). + ellipsoidal_height_topocentric_origin: float, default=0.0 + Ellipsoidal height of topocentric origin. + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + + """ + nsper_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Vertical Perspective", + "id": {"authority": "EPSG", "code": 9838}, + }, + "parameters": [ + { + "name": "Latitude of topocentric origin", + "value": latitude_topocentric_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8834}, + }, + { + "name": "Longitude of topocentric origin", + "value": longitude_topocentric_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8835}, + }, + { + "name": "Ellipsoidal height of topocentric origin", + "value": ellipsoidal_height_topocentric_origin, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8836}, + }, + { + "name": "Viewpoint height", + "value": viewpoint_height, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8840}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(nsper_json)
+
+ + + +
+[docs] +class RotatedLatitudeLongitudeConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Rotated Latitude Longitude conversion. + + :ref:`PROJ docs <ob_tran>` + """ + +
+[docs] + def __new__(cls, o_lat_p: float, o_lon_p: float, lon_0: float = 0.0): + """ + Parameters + ---------- + o_lat_p: float + Latitude of the North pole of the unrotated source CRS, + expressed in the rotated geographic CRS. + o_lon_p: float + Longitude of the North pole of the unrotated source CRS, + expressed in the rotated geographic CRS. + lon_0: float, default=0.0 + Longitude of projection center. + + """ + rot_latlon_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": {"name": "PROJ ob_tran o_proj=longlat"}, + "parameters": [ + {"name": "o_lat_p", "value": o_lat_p, "unit": "degree"}, + {"name": "o_lon_p", "value": o_lon_p, "unit": "degree"}, + {"name": "lon_0", "value": lon_0, "unit": "degree"}, + ], + } + return cls.from_json_dict(rot_latlon_json)
+
+ + + +
+[docs] +class PoleRotationNetCDFCFConversion(CoordinateOperation): + """ + .. versionadded:: 3.3.0 + + Class for constructing the Pole rotation (netCDF CF convention) conversion. + + http://cfconventions.org/cf-conventions/cf-conventions.html#_rotated_pole + + :ref:`PROJ docs <ob_tran>` + """ + +
+[docs] + def __new__( + cls, + grid_north_pole_latitude: float, + grid_north_pole_longitude: float, + north_pole_grid_longitude: float = 0.0, + ): + """ + Parameters + ---------- + grid_north_pole_latitude: float + Latitude of the North pole of the unrotated source CRS, + expressed in the rotated geographic CRS (o_lat_p) + grid_north_pole_longitude: float + Longitude of projection center (lon_0 - 180). + north_pole_grid_longitude: float, default=0.0 + Longitude of the North pole of the unrotated source CRS, + expressed in the rotated geographic CRS (o_lon_p). + """ + rot_latlon_json = { + "$schema": "https://proj.org/schemas/v0.4/projjson.schema.json", + "type": "Conversion", + "name": "Pole rotation (netCDF CF convention)", + "method": {"name": "Pole rotation (netCDF CF convention)"}, + "parameters": [ + { + "name": "Grid north pole latitude (netCDF CF convention)", + "value": grid_north_pole_latitude, + "unit": "degree", + }, + { + "name": "Grid north pole longitude (netCDF CF convention)", + "value": grid_north_pole_longitude, + "unit": "degree", + }, + { + "name": "North pole grid longitude (netCDF CF convention)", + "value": north_pole_grid_longitude, + "unit": "degree", + }, + ], + } + return cls.from_json_dict(rot_latlon_json)
+
+ + + +
+[docs] +class EquidistantCylindricalConversion(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the Equidistant Cylintrical (Plate Carrée) conversion. + + :ref:`PROJ docs <eqc>` + """ + +
+[docs] + def __new__( + cls, + latitude_first_parallel: float = 0.0, + latitude_natural_origin: float = 0.0, + longitude_natural_origin: float = 0.0, + false_easting: float = 0.0, + false_northing: float = 0.0, + ): + """ + Parameters + ---------- + latitude_first_parallel: float, default=0.0 + Latitude of 1st standard parallel (lat_ts). + latitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + longitude_natural_origin: float, default=0.0 + Longitude of projection center (lon_0). + false_easting: float, default=0.0 + False easting (x_0). + false_northing: float, default=0.0 + False northing (y_0). + """ + eqc_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Conversion", + "name": "unknown", + "method": { + "name": "Equidistant Cylindrical", + "id": {"authority": "EPSG", "code": 1028}, + }, + "parameters": [ + { + "name": "Latitude of 1st standard parallel", + "value": latitude_first_parallel, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8823}, + }, + { + "name": "Latitude of natural origin", + "value": latitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8801}, + }, + { + "name": "Longitude of natural origin", + "value": longitude_natural_origin, + "unit": "degree", + "id": {"authority": "EPSG", "code": 8802}, + }, + { + "name": "False easting", + "value": false_easting, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8806}, + }, + { + "name": "False northing", + "value": false_northing, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8807}, + }, + ], + } + return cls.from_json_dict(eqc_json)
+
+ + + +# Add an alias for PlateCarree +PlateCarreeConversion = EquidistantCylindricalConversion + + +
+[docs] +class ToWGS84Transformation(CoordinateOperation): + """ + .. versionadded:: 2.5.0 + + Class for constructing the ToWGS84 Transformation. + """ + +
+[docs] + def __new__( + cls, + source_crs: Any, + x_axis_translation: float = 0, + y_axis_translation: float = 0, + z_axis_translation: float = 0, + x_axis_rotation: float = 0, + y_axis_rotation: float = 0, + z_axis_rotation: float = 0, + scale_difference: float = 0, + ): + """ + Parameters + ---------- + source_crs: Any + Input to create the Source CRS. + x_axis_translation: float, default=0.0 + X-axis translation. + y_axis_translation: float, default=0.0 + Y-axis translation. + z_axis_translation: float, default=0.0 + Z-axis translation. + x_axis_rotation: float, default=0.0 + X-axis rotation. + y_axis_rotation: float, default=0.0 + Y-axis rotation. + z_axis_rotation: float, default=0.0 + Z-axis rotation. + scale_difference: float, default=0.0 + Scale difference. + """ + # pylint: disable=import-outside-toplevel + from pyproj.crs import CRS + + towgs84_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Transformation", + "name": "Transformation from unknown to WGS84", + "source_crs": CRS.from_user_input(source_crs).to_json_dict(), + "target_crs": { + "type": "GeographicCRS", + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "name": "WGS 84", + "semi_major_axis": 6378137, + "inverse_flattening": 298.257223563, + }, + }, + "coordinate_system": { + "subtype": "ellipsoidal", + "axis": [ + { + "name": "Latitude", + "abbreviation": "lat", + "direction": "north", + "unit": "degree", + }, + { + "name": "Longitude", + "abbreviation": "lon", + "direction": "east", + "unit": "degree", + }, + ], + }, + "id": {"authority": "EPSG", "code": 4326}, + }, + "method": { + "name": "Position Vector transformation (geog2D domain)", + "id": {"authority": "EPSG", "code": 9606}, + }, + "parameters": [ + { + "name": "X-axis translation", + "value": x_axis_translation, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8605}, + }, + { + "name": "Y-axis translation", + "value": y_axis_translation, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8606}, + }, + { + "name": "Z-axis translation", + "value": z_axis_translation, + "unit": "metre", + "id": {"authority": "EPSG", "code": 8607}, + }, + { + "name": "X-axis rotation", + "value": x_axis_rotation, + "unit": { + "type": "AngularUnit", + "name": "arc-second", + "conversion_factor": 4.84813681109536e-06, + }, + "id": {"authority": "EPSG", "code": 8608}, + }, + { + "name": "Y-axis rotation", + "value": y_axis_rotation, + "unit": { + "type": "AngularUnit", + "name": "arc-second", + "conversion_factor": 4.84813681109536e-06, + }, + "id": {"authority": "EPSG", "code": 8609}, + }, + { + "name": "Z-axis rotation", + "value": z_axis_rotation, + "unit": { + "type": "AngularUnit", + "name": "arc-second", + "conversion_factor": 4.84813681109536e-06, + }, + "id": {"authority": "EPSG", "code": 8610}, + }, + { + "name": "Scale difference", + "value": scale_difference, + "unit": { + "type": "ScaleUnit", + "name": "parts per million", + "conversion_factor": 1e-06, + }, + "id": {"authority": "EPSG", "code": 8611}, + }, + ], + } + + return cls.from_json_dict(towgs84_json)
+
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/crs/coordinate_system.html b/3.7.0/_modules/pyproj/crs/coordinate_system.html new file mode 100644 index 000000000..677415ef0 --- /dev/null +++ b/3.7.0/_modules/pyproj/crs/coordinate_system.html @@ -0,0 +1,716 @@ + + + + + + + + pyproj.crs.coordinate_system - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.crs.coordinate_system

+"""
+This module is for building coordinate systems to be used when
+building a CRS.
+"""
+
+from pyproj._crs import CoordinateSystem
+from pyproj.crs.enums import (
+    Cartesian2DCSAxis,
+    Ellipsoidal2DCSAxis,
+    Ellipsoidal3DCSAxis,
+    VerticalCSAxis,
+)
+
+# useful constants to use when setting PROJ JSON units
+UNIT_METRE = "metre"
+UNIT_DEGREE = "degree"
+UNIT_FT = {"type": "LinearUnit", "name": "foot", "conversion_factor": 0.3048}
+UNIT_US_FT = {
+    "type": "LinearUnit",
+    "name": "US survey foot",
+    "conversion_factor": 0.304800609601219,
+}
+
+_ELLIPSOIDAL_2D_AXIS_MAP = {
+    Ellipsoidal2DCSAxis.LONGITUDE_LATITUDE: [
+        {
+            "name": "Longitude",
+            "abbreviation": "lon",
+            "direction": "east",
+            "unit": UNIT_DEGREE,
+        },
+        {
+            "name": "Latitude",
+            "abbreviation": "lat",
+            "direction": "north",
+            "unit": UNIT_DEGREE,
+        },
+    ],
+    Ellipsoidal2DCSAxis.LATITUDE_LONGITUDE: [
+        {
+            "name": "Latitude",
+            "abbreviation": "lat",
+            "direction": "north",
+            "unit": UNIT_DEGREE,
+        },
+        {
+            "name": "Longitude",
+            "abbreviation": "lon",
+            "direction": "east",
+            "unit": UNIT_DEGREE,
+        },
+    ],
+}
+
+
+
+[docs] +class Ellipsoidal2DCS(CoordinateSystem): + """ + .. versionadded:: 2.5.0 + + This generates an Ellipsoidal 2D Coordinate System + """ + +
+[docs] + def __new__( + cls, + axis: Ellipsoidal2DCSAxis | str = Ellipsoidal2DCSAxis.LONGITUDE_LATITUDE, + ): + """ + Parameters + ---------- + axis: :class:`pyproj.crs.enums.Ellipsoidal2DCSAxis` or str, optional + This is the axis order of the coordinate system. Default is + :attr:`pyproj.crs.enums.Ellipsoidal2DCSAxis.LONGITUDE_LATITUDE`. + """ + return cls.from_json_dict( + { + "type": "CoordinateSystem", + "subtype": "ellipsoidal", + "axis": _ELLIPSOIDAL_2D_AXIS_MAP[Ellipsoidal2DCSAxis.create(axis)], + } + )
+
+ + + +_ELLIPSOIDAL_3D_AXIS_MAP = { + Ellipsoidal3DCSAxis.LONGITUDE_LATITUDE_HEIGHT: [ + { + "name": "Longitude", + "abbreviation": "lon", + "direction": "east", + "unit": UNIT_DEGREE, + }, + { + "name": "Latitude", + "abbreviation": "lat", + "direction": "north", + "unit": UNIT_DEGREE, + }, + { + "name": "Ellipsoidal height", + "abbreviation": "h", + "direction": "up", + "unit": UNIT_METRE, + }, + ], + Ellipsoidal3DCSAxis.LATITUDE_LONGITUDE_HEIGHT: [ + { + "name": "Latitude", + "abbreviation": "lat", + "direction": "north", + "unit": UNIT_DEGREE, + }, + { + "name": "Longitude", + "abbreviation": "lon", + "direction": "east", + "unit": UNIT_DEGREE, + }, + { + "name": "Ellipsoidal height", + "abbreviation": "h", + "direction": "up", + "unit": UNIT_METRE, + }, + ], +} + + +
+[docs] +class Ellipsoidal3DCS(CoordinateSystem): + """ + .. versionadded:: 2.5.0 + + This generates an Ellipsoidal 3D Coordinate System + """ + +
+[docs] + def __new__( + cls, + axis: Ellipsoidal3DCSAxis | str = Ellipsoidal3DCSAxis.LONGITUDE_LATITUDE_HEIGHT, + ): + """ + Parameters + ---------- + axis: :class:`pyproj.crs.enums.Ellipsoidal3DCSAxis` or str, optional + This is the axis order of the coordinate system. Default is + :attr:`pyproj.crs.enums.Ellipsoidal3DCSAxis.LONGITUDE_LATITUDE_HEIGHT`. + """ + return cls.from_json_dict( + { + "type": "CoordinateSystem", + "subtype": "ellipsoidal", + "axis": _ELLIPSOIDAL_3D_AXIS_MAP[Ellipsoidal3DCSAxis.create(axis)], + } + )
+
+ + + +_CARTESIAN_2D_AXIS_MAP = { + Cartesian2DCSAxis.EASTING_NORTHING: [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "east", + "unit": UNIT_METRE, + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": UNIT_METRE, + }, + ], + Cartesian2DCSAxis.NORTHING_EASTING: [ + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": UNIT_METRE, + }, + { + "name": "Easting", + "abbreviation": "E", + "direction": "east", + "unit": UNIT_METRE, + }, + ], + Cartesian2DCSAxis.EASTING_NORTHING_FT: [ + {"name": "Easting", "abbreviation": "X", "direction": "east", "unit": UNIT_FT}, + { + "name": "Northing", + "abbreviation": "Y", + "direction": "north", + "unit": UNIT_FT, + }, + ], + Cartesian2DCSAxis.NORTHING_EASTING_FT: [ + { + "name": "Northing", + "abbreviation": "Y", + "direction": "north", + "unit": UNIT_FT, + }, + {"name": "Easting", "abbreviation": "X", "direction": "east", "unit": UNIT_FT}, + ], + Cartesian2DCSAxis.EASTING_NORTHING_US_FT: [ + { + "name": "Easting", + "abbreviation": "X", + "direction": "east", + "unit": UNIT_US_FT, + }, + { + "name": "Northing", + "abbreviation": "Y", + "direction": "north", + "unit": UNIT_US_FT, + }, + ], + Cartesian2DCSAxis.NORTHING_EASTING_US_FT: [ + { + "name": "Northing", + "abbreviation": "Y", + "direction": "north", + "unit": UNIT_US_FT, + }, + { + "name": "Easting", + "abbreviation": "X", + "direction": "east", + "unit": UNIT_US_FT, + }, + ], + Cartesian2DCSAxis.NORTH_POLE_EASTING_SOUTH_NORTHING_SOUTH: [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "south", + "unit": UNIT_METRE, + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "south", + "unit": UNIT_METRE, + }, + ], + Cartesian2DCSAxis.SOUTH_POLE_EASTING_NORTH_NORTHING_NORTH: [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "north", + "unit": UNIT_METRE, + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": UNIT_METRE, + }, + ], + Cartesian2DCSAxis.WESTING_SOUTHING: [ + { + "name": "Easting", + "abbreviation": "Y", + "direction": "west", + "unit": UNIT_METRE, + }, + { + "name": "Northing", + "abbreviation": "X", + "direction": "south", + "unit": UNIT_METRE, + }, + ], +} + + +
+[docs] +class Cartesian2DCS(CoordinateSystem): + """ + .. versionadded:: 2.5.0 + + This generates an Cartesian 2D Coordinate System + """ + +
+[docs] + def __new__( + cls, axis: Cartesian2DCSAxis | str = Cartesian2DCSAxis.EASTING_NORTHING + ): + """ + Parameters + ---------- + axis: :class:`pyproj.crs.enums.Cartesian2DCSAxis` or str, optional + This is the axis order of the coordinate system. + Default is :attr:`pyproj.crs.enums.Cartesian2DCSAxis.EASTING_NORTHING`. + """ + return cls.from_json_dict( + { + "type": "CoordinateSystem", + "subtype": "Cartesian", + "axis": _CARTESIAN_2D_AXIS_MAP[Cartesian2DCSAxis.create(axis)], + } + )
+
+ + + +_VERTICAL_AXIS_MAP = { + VerticalCSAxis.GRAVITY_HEIGHT: { + "name": "Gravity-related height", + "abbreviation": "H", + "direction": "up", + "unit": UNIT_METRE, + }, + VerticalCSAxis.GRAVITY_HEIGHT_US_FT: { + "name": "Gravity-related height", + "abbreviation": "H", + "direction": "up", + "unit": UNIT_US_FT, + }, + VerticalCSAxis.GRAVITY_HEIGHT_FT: { + "name": "Gravity-related height", + "abbreviation": "H", + "direction": "up", + "unit": UNIT_FT, + }, + VerticalCSAxis.DEPTH: { + "name": "Depth", + "abbreviation": "D", + "direction": "down", + "unit": UNIT_METRE, + }, + VerticalCSAxis.DEPTH_US_FT: { + "name": "Depth", + "abbreviation": "D", + "direction": "down", + "unit": UNIT_US_FT, + }, + VerticalCSAxis.DEPTH_FT: { + "name": "Depth", + "abbreviation": "D", + "direction": "down", + "unit": UNIT_FT, + }, + VerticalCSAxis.UP: { + "name": "up", + "abbreviation": "H", + "direction": "up", + "unit": UNIT_METRE, + }, + VerticalCSAxis.UP_FT: { + "name": "up", + "abbreviation": "H", + "direction": "up", + "unit": UNIT_FT, + }, + VerticalCSAxis.UP_US_FT: { + "name": "up", + "abbreviation": "H", + "direction": "up", + "unit": UNIT_US_FT, + }, +} + + +
+[docs] +class VerticalCS(CoordinateSystem): + """ + .. versionadded:: 2.5.0 + + This generates an Vertical Coordinate System + """ + +
+[docs] + def __new__(cls, axis: VerticalCSAxis | str = VerticalCSAxis.GRAVITY_HEIGHT): + """ + Parameters + ---------- + axis: :class:`pyproj.crs.enums.VerticalCSAxis` or str, optional + This is the axis direction of the coordinate system. + Default is :attr:`pyproj.crs.enums.VerticalCSAxis.GRAVITY_HEIGHT`. + """ + return cls.from_json_dict( + { + "type": "CoordinateSystem", + "subtype": "vertical", + "axis": [_VERTICAL_AXIS_MAP[VerticalCSAxis.create(axis)]], + } + )
+
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/crs/crs.html b/3.7.0/_modules/pyproj/crs/crs.html new file mode 100644 index 000000000..47177c4e5 --- /dev/null +++ b/3.7.0/_modules/pyproj/crs/crs.html @@ -0,0 +1,2558 @@ + + + + + + + + pyproj.crs.crs - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.crs.crs

+"""
+This module interfaces with PROJ to produce a pythonic interface
+to the coordinate reference system (CRS) information.
+"""
+
+# pylint: disable=too-many-lines
+import json
+import re
+import threading
+import warnings
+from collections.abc import Callable
+from typing import Any, Optional
+
+from pyproj._crs import (
+    _CRS,
+    AreaOfUse,
+    AuthorityMatchInfo,
+    Axis,
+    CoordinateOperation,
+    CoordinateSystem,
+    Datum,
+    Ellipsoid,
+    PrimeMeridian,
+    _load_proj_json,
+    is_proj,
+    is_wkt,
+)
+from pyproj.crs._cf1x8 import (
+    _GEOGRAPHIC_GRID_MAPPING_NAME_MAP,
+    _GRID_MAPPING_NAME_MAP,
+    _INVERSE_GEOGRAPHIC_GRID_MAPPING_NAME_MAP,
+    _INVERSE_GRID_MAPPING_NAME_MAP,
+    _horizontal_datum_from_params,
+    _try_list_if_string,
+)
+from pyproj.crs.coordinate_operation import ToWGS84Transformation
+from pyproj.crs.coordinate_system import Cartesian2DCS, Ellipsoidal2DCS, VerticalCS
+from pyproj.enums import ProjVersion, WktVersion
+from pyproj.exceptions import CRSError
+from pyproj.geod import Geod
+
+_RE_PROJ_PARAM = re.compile(
+    r"""
+    \+              # parameter starts with '+' character
+    (?P<param>\w+)    # capture parameter name
+    \=?             # match both key only and key-value parameters
+    (?P<value>\S+)? # capture all characters up to next space (None if no value)
+    \s*?            # consume remaining whitespace, if any
+""",
+    re.X,
+)
+
+
+class CRSLocal(threading.local):
+    """
+    Threading local instance for cython CRS class.
+
+    For more details, see:
+    https://github.com/pyproj4/pyproj/issues/782
+    """
+
+    def __init__(self):
+        self.crs = None  # Initialises in each thread
+        super().__init__()
+
+
+def _prepare_from_dict(projparams: dict, allow_json: bool = True) -> str:
+    if not isinstance(projparams, dict):
+        raise CRSError("CRS input is not a dict")
+    # check if it is a PROJ JSON dict
+    if "proj" not in projparams and "init" not in projparams and allow_json:
+        return json.dumps(projparams)
+    # convert a dict to a proj string.
+    pjargs = []
+    for key, value in projparams.items():
+        # the towgs84 as list
+        if isinstance(value, (list, tuple)):
+            value = ",".join([str(val) for val in value])
+        # issue 183 (+ no_rot)
+        if value is None or str(value) == "True":
+            pjargs.append(f"+{key}")
+        elif str(value) == "False":
+            pass
+        else:
+            pjargs.append(f"+{key}={value}")
+    return _prepare_from_string(" ".join(pjargs))
+
+
+def _prepare_from_proj_string(in_crs_string: str) -> str:
+    in_crs_string = re.sub(r"[\s+]?=[\s+]?", "=", in_crs_string.lstrip())
+    # make sure the projection starts with +proj or +init
+    starting_params = ("+init", "+proj", "init", "proj")
+    if not in_crs_string.startswith(starting_params):
+        kvpairs: list[str] = []
+        first_item_inserted = False
+        for kvpair in in_crs_string.split():
+            if not first_item_inserted and (kvpair.startswith(starting_params)):
+                kvpairs.insert(0, kvpair)
+                first_item_inserted = True
+            else:
+                kvpairs.append(kvpair)
+        in_crs_string = " ".join(kvpairs)
+
+    # make sure it is the CRS type
+    if "type=crs" not in in_crs_string:
+        if "+" in in_crs_string:
+            in_crs_string += " +type=crs"
+        else:
+            in_crs_string += " type=crs"
+
+    # look for EPSG, replace with epsg (EPSG only works
+    # on case-insensitive filesystems).
+    in_crs_string = in_crs_string.replace("+init=EPSG", "+init=epsg").strip()
+    if in_crs_string.startswith(("+init", "init")):
+        warnings.warn(
+            "'+init=<authority>:<code>' syntax is deprecated. "
+            "'<authority>:<code>' is the preferred initialization method. "
+            "When making the change, be mindful of axis order changes: "
+            "https://pyproj4.github.io/pyproj/stable/gotchas.html"
+            "#axis-order-changes-in-proj-6",
+            FutureWarning,
+            stacklevel=2,
+        )
+    return in_crs_string
+
+
+def _prepare_from_string(in_crs_string: str) -> str:
+    if not isinstance(in_crs_string, str):
+        raise CRSError("CRS input is not a string")
+    if not in_crs_string:
+        raise CRSError(f"CRS string is empty or invalid: {in_crs_string!r}")
+    if "{" in in_crs_string:
+        # may be json, try to decode it
+        try:
+            crs_dict = json.loads(in_crs_string, strict=False)
+        except ValueError as err:
+            raise CRSError("CRS appears to be JSON but is not valid") from err
+
+        if not crs_dict:
+            raise CRSError("CRS is empty JSON")
+        in_crs_string = _prepare_from_dict(crs_dict)
+    elif is_proj(in_crs_string):
+        in_crs_string = _prepare_from_proj_string(in_crs_string)
+    return in_crs_string
+
+
+def _prepare_from_authority(auth_name: str, auth_code: str | int):
+    return f"{auth_name}:{auth_code}"
+
+
+def _prepare_from_epsg(auth_code: str | int):
+    return _prepare_from_authority("EPSG", auth_code)
+
+
+def _is_epsg_code(auth_code: Any) -> bool:
+    if isinstance(auth_code, int):
+        return True
+    if isinstance(auth_code, str) and auth_code.isnumeric():
+        return True
+    if hasattr(auth_code, "shape") and auth_code.shape == ():
+        return True
+    return False
+
+
+
+[docs] +class CRS: + """ + A pythonic Coordinate Reference System manager. + + .. versionadded:: 2.0.0 + + See: :c:func:`proj_create` + + The functionality is based on other fantastic projects: + + * `rasterio <https://github.com/mapbox/rasterio/blob/c13f0943b95c0eaa36ff3f620bd91107aa67b381/rasterio/_crs.pyx>`_ # noqa: E501 + * `opendatacube <https://github.com/opendatacube/datacube-core/blob/83bae20d2a2469a6417097168fd4ede37fd2abe5/datacube/utils/geometry/_base.py>`_ # noqa: E501 + + Attributes + ---------- + srs: str + The string form of the user input used to create the CRS. + + """ + +
+[docs] + def __init__(self, projparams: Any | None = None, **kwargs) -> None: + """ + Initialize a CRS class instance with: + - PROJ string + - Dictionary of PROJ parameters + - PROJ keyword arguments for parameters + - JSON string with PROJ parameters + - CRS WKT string + - An authority string [i.e. 'epsg:4326'] + - An EPSG integer code [i.e. 4326] + - A tuple of ("auth_name": "auth_code") [i.e ('epsg', '4326')] + - An object with a `to_wkt` method. + - A :class:`pyproj.crs.CRS` class + + Example usage: + + >>> from pyproj import CRS + >>> crs_utm = CRS.from_user_input(26915) + >>> crs_utm + <Projected CRS: EPSG:26915> + Name: NAD83 / UTM zone 15N + Axis Info [cartesian]: + - E[east]: Easting (metre) + - N[north]: Northing (metre) + Area of Use: + - name: North America - 96°W to 90°W and NAD83 by country + - bounds: (-96.0, 25.61, -90.0, 84.0) + Coordinate Operation: + - name: UTM zone 15N + - method: Transverse Mercator + Datum: North American Datum 1983 + - Ellipsoid: GRS 1980 + - Prime Meridian: Greenwich + <BLANKLINE> + >>> crs_utm.area_of_use.bounds + (-96.0, 25.61, -90.0, 84.0) + >>> crs_utm.ellipsoid + ELLIPSOID["GRS 1980",6378137,298.257222101, + LENGTHUNIT["metre",1], + ID["EPSG",7019]] + >>> crs_utm.ellipsoid.inverse_flattening + 298.257222101 + >>> crs_utm.ellipsoid.semi_major_metre + 6378137.0 + >>> crs_utm.ellipsoid.semi_minor_metre + 6356752.314140356 + >>> crs_utm.prime_meridian + PRIMEM["Greenwich",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8901]] + >>> crs_utm.prime_meridian.unit_name + 'degree' + >>> crs_utm.prime_meridian.unit_conversion_factor + 0.017453292519943295 + >>> crs_utm.prime_meridian.longitude + 0.0 + >>> crs_utm.datum + DATUM["North American Datum 1983", + ELLIPSOID["GRS 1980",6378137,298.257222101, + LENGTHUNIT["metre",1]], + ID["EPSG",6269]] + >>> crs_utm.coordinate_system + CS[Cartesian,2], + AXIS["(E)",east, + ORDER[1], + LENGTHUNIT["metre",1, + ID["EPSG",9001]]], + AXIS["(N)",north, + ORDER[2], + LENGTHUNIT["metre",1, + ID["EPSG",9001]]] + >>> print(crs_utm.coordinate_operation.to_wkt(pretty=True)) + CONVERSION["UTM zone 15N", + METHOD["Transverse Mercator", + ID["EPSG",9807]], + PARAMETER["Latitude of natural origin",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8801]], + PARAMETER["Longitude of natural origin",-93, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8802]], + PARAMETER["Scale factor at natural origin",0.9996, + SCALEUNIT["unity",1], + ID["EPSG",8805]], + PARAMETER["False easting",500000, + LENGTHUNIT["metre",1], + ID["EPSG",8806]], + PARAMETER["False northing",0, + LENGTHUNIT["metre",1], + ID["EPSG",8807]], + ID["EPSG",16015]] + >>> crs = CRS(proj='utm', zone=10, ellps='WGS84') + >>> print(crs.to_wkt(pretty=True)) + PROJCRS["unknown", + BASEGEOGCRS["unknown", + DATUM["Unknown based on WGS84 ellipsoid", + ELLIPSOID["WGS 84",6378137,298.257223563, + LENGTHUNIT["metre",1], + ID["EPSG",7030]]], + PRIMEM["Greenwich",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8901]]], + CONVERSION["UTM zone 10N", + METHOD["Transverse Mercator", + ID["EPSG",9807]], + PARAMETER["Latitude of natural origin",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8801]], + PARAMETER["Longitude of natural origin",-123, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8802]], + PARAMETER["Scale factor at natural origin",0.9996, + SCALEUNIT["unity",1], + ID["EPSG",8805]], + PARAMETER["False easting",500000, + LENGTHUNIT["metre",1], + ID["EPSG",8806]], + PARAMETER["False northing",0, + LENGTHUNIT["metre",1], + ID["EPSG",8807]], + ID["EPSG",16010]], + CS[Cartesian,2], + AXIS["(E)",east, + ORDER[1], + LENGTHUNIT["metre",1, + ID["EPSG",9001]]], + AXIS["(N)",north, + ORDER[2], + LENGTHUNIT["metre",1, + ID["EPSG",9001]]]] + >>> geod = crs.get_geod() + >>> f"+a={geod.a:.0f} +f={geod.f:.8f}" + '+a=6378137 +f=0.00335281' + >>> crs.is_projected + True + >>> crs.is_geographic + False + """ + projstring = "" + + if projparams: + if isinstance(projparams, _CRS): + projstring = projparams.srs + elif _is_epsg_code(projparams): + projstring = _prepare_from_epsg(projparams) + elif isinstance(projparams, str): + projstring = _prepare_from_string(projparams) + elif isinstance(projparams, dict): + projstring = _prepare_from_dict(projparams) + elif isinstance(projparams, (list, tuple)) and len(projparams) == 2: + projstring = _prepare_from_authority(*projparams) + elif hasattr(projparams, "to_wkt"): + projstring = projparams.to_wkt() # type: ignore + else: + raise CRSError(f"Invalid CRS input: {projparams!r}") + + if kwargs: + projkwargs = _prepare_from_dict(kwargs, allow_json=False) + projstring = _prepare_from_string(" ".join((projstring, projkwargs))) + + self.srs = projstring + self._local = CRSLocal() + if isinstance(projparams, _CRS): + self._local.crs = projparams + else: + self._local.crs = _CRS(self.srs)
+ + + @property + def _crs(self): + """ + Retrieve the Cython based _CRS object for this thread. + """ + if self._local.crs is None: + self._local.crs = _CRS(self.srs) + return self._local.crs + +
+[docs] + @classmethod + def from_authority(cls, auth_name: str, code: str | int) -> "CRS": + """ + .. versionadded:: 2.2.0 + + Make a CRS from an authority name and authority code + + Parameters + ---------- + auth_name: str + The name of the authority. + code : int or str + The code used by the authority. + + Returns + ------- + CRS + """ + return cls.from_user_input(_prepare_from_authority(auth_name, code))
+ + +
+[docs] + @classmethod + def from_epsg(cls, code: str | int) -> "CRS": + """Make a CRS from an EPSG code + + Parameters + ---------- + code : int or str + An EPSG code. + + Returns + ------- + CRS + """ + return cls.from_user_input(_prepare_from_epsg(code))
+ + +
+[docs] + @classmethod + def from_proj4(cls, in_proj_string: str) -> "CRS": + """ + .. versionadded:: 2.2.0 + + Make a CRS from a PROJ string + + Parameters + ---------- + in_proj_string : str + A PROJ string. + + Returns + ------- + CRS + """ + if not is_proj(in_proj_string): + raise CRSError(f"Invalid PROJ string: {in_proj_string}") + return cls.from_user_input(_prepare_from_proj_string(in_proj_string))
+ + +
+[docs] + @classmethod + def from_wkt(cls, in_wkt_string: str) -> "CRS": + """ + .. versionadded:: 2.2.0 + + Make a CRS from a WKT string + + Parameters + ---------- + in_wkt_string : str + A WKT string. + + Returns + ------- + CRS + """ + if not is_wkt(in_wkt_string): + raise CRSError(f"Invalid WKT string: {in_wkt_string}") + return cls.from_user_input(_prepare_from_string(in_wkt_string))
+ + +
+[docs] + @classmethod + def from_string(cls, in_crs_string: str) -> "CRS": + """ + Make a CRS from: + + Initialize a CRS class instance with: + - PROJ string + - JSON string with PROJ parameters + - CRS WKT string + - An authority string [i.e. 'epsg:4326'] + + Parameters + ---------- + in_crs_string : str + An EPSG, PROJ, or WKT string. + + Returns + ------- + CRS + """ + return cls.from_user_input(_prepare_from_string(in_crs_string))
+ + +
+[docs] + def to_string(self) -> str: + """ + .. versionadded:: 2.2.0 + + Convert the CRS to a string. + + It attempts to convert it to the authority string. + Otherwise, it uses the string format of the user + input to create the CRS. + + Returns + ------- + str + """ + auth_info = self.to_authority(min_confidence=100) + if auth_info: + return ":".join(auth_info) + return self.srs
+ + +
+[docs] + @classmethod + def from_user_input(cls, value: Any, **kwargs) -> "CRS": + """ + Initialize a CRS class instance with: + - PROJ string + - Dictionary of PROJ parameters + - PROJ keyword arguments for parameters + - JSON string with PROJ parameters + - CRS WKT string + - An authority string [i.e. 'epsg:4326'] + - An EPSG integer code [i.e. 4326] + - A tuple of ("auth_name": "auth_code") [i.e ('epsg', '4326')] + - An object with a `to_wkt` method. + - A :class:`pyproj.crs.CRS` class + + Parameters + ---------- + value : obj + A Python int, dict, or str. + + Returns + ------- + CRS + """ + if isinstance(value, cls): + return value + return cls(value, **kwargs)
+ + +
+[docs] + def get_geod(self) -> Geod | None: + """ + Returns + ------- + pyproj.geod.Geod: + Geod object based on the ellipsoid. + """ + if self.ellipsoid is None: + return None + return Geod( + a=self.ellipsoid.semi_major_metre, + rf=self.ellipsoid.inverse_flattening, + b=self.ellipsoid.semi_minor_metre, + )
+ + +
+[docs] + @classmethod + def from_dict(cls, proj_dict: dict) -> "CRS": + """ + .. versionadded:: 2.2.0 + + Make a CRS from a dictionary of PROJ parameters. + + Parameters + ---------- + proj_dict : str + PROJ params in dict format. + + Returns + ------- + CRS + """ + return cls.from_user_input(_prepare_from_dict(proj_dict))
+ + +
+[docs] + @classmethod + def from_json(cls, crs_json: str) -> "CRS": + """ + .. versionadded:: 2.4.0 + + Create CRS from a CRS JSON string. + + Parameters + ---------- + crs_json: str + CRS JSON string. + + Returns + ------- + CRS + """ + return cls.from_user_input(_load_proj_json(crs_json))
+ + +
+[docs] + @classmethod + def from_json_dict(cls, crs_dict: dict) -> "CRS": + """ + .. versionadded:: 2.4.0 + + Create CRS from a JSON dictionary. + + Parameters + ---------- + crs_dict: dict + CRS dictionary. + + Returns + ------- + CRS + """ + return cls.from_user_input(json.dumps(crs_dict))
+ + +
+[docs] + def to_dict(self) -> dict: + """ + .. versionadded:: 2.2.0 + + Converts the CRS to dictionary of PROJ parameters. + + .. warning:: You will likely lose important projection + information when converting to a PROJ string from + another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems # noqa: E501 + + Returns + ------- + dict: + PROJ params in dict format. + + """ + + proj_string = self.to_proj4() + if proj_string is None: + return {} + + def _parse(val): + if val.lower() == "true": + return True + if val.lower() == "false": + return False + try: + return int(val) + except ValueError: + pass + try: + return float(val) + except ValueError: + pass + return _try_list_if_string(val) + + proj_dict = {} + for param in _RE_PROJ_PARAM.finditer(proj_string): + key, value = param.groups() + if value is not None: + value = _parse(value) + if value is not False: + proj_dict[key] = value + + return proj_dict
+ + +
+[docs] + def to_cf( + self, + wkt_version: WktVersion | str = WktVersion.WKT2_2019, + errcheck: bool = False, + ) -> dict: + """ + .. versionadded:: 2.2.0 + + This converts a :obj:`pyproj.crs.CRS` object + to a Climate and Forecast (CF) Grid Mapping Version 1.8 dict. + + :ref:`build_crs_cf` + + Parameters + ---------- + wkt_version: str or pyproj.enums.WktVersion + Version of WKT supported by CRS.to_wkt. + Default is :attr:`pyproj.enums.WktVersion.WKT2_2019`. + errcheck: bool, default=False + If True, will warn when parameters are ignored. + + Returns + ------- + dict: + CF-1.8 version of the projection. + + """ + # pylint: disable=too-many-branches,too-many-return-statements + cf_dict: dict[str, Any] = {"crs_wkt": self.to_wkt(wkt_version)} + + # handle bound CRS + if ( + self.is_bound + and self.coordinate_operation + and self.coordinate_operation.towgs84 + and self.source_crs + ): + sub_cf: dict[str, Any] = self.source_crs.to_cf( + wkt_version=wkt_version, + errcheck=errcheck, + ) + sub_cf.pop("crs_wkt") + cf_dict.update(sub_cf) + cf_dict["towgs84"] = self.coordinate_operation.towgs84 + return cf_dict + + # handle compound CRS + if self.is_compound: + for sub_crs in self.sub_crs_list: + sub_cf = sub_crs.to_cf(wkt_version=wkt_version, errcheck=errcheck) + sub_cf.pop("crs_wkt") + cf_dict.update(sub_cf) + return cf_dict + + # handle vertical CRS + if self.is_vertical: + vert_json = self.to_json_dict() + if "geoid_model" in vert_json: + cf_dict["geoid_name"] = vert_json["geoid_model"]["name"] + if self.datum: + cf_dict["geopotential_datum_name"] = self.datum.name + return cf_dict + + # write out datum parameters + if self.ellipsoid: + cf_dict.update( + semi_major_axis=self.ellipsoid.semi_major_metre, + semi_minor_axis=self.ellipsoid.semi_minor_metre, + inverse_flattening=self.ellipsoid.inverse_flattening, + ) + cf_dict["reference_ellipsoid_name"] = self.ellipsoid.name + if self.prime_meridian: + cf_dict["longitude_of_prime_meridian"] = self.prime_meridian.longitude + cf_dict["prime_meridian_name"] = self.prime_meridian.name + + # handle geographic CRS + if self.geodetic_crs: + cf_dict["geographic_crs_name"] = self.geodetic_crs.name + if self.geodetic_crs.datum: + cf_dict["horizontal_datum_name"] = self.geodetic_crs.datum.name + + if self.is_geographic: + if self.coordinate_operation: + if ( + self.coordinate_operation.method_name.lower() + not in _INVERSE_GEOGRAPHIC_GRID_MAPPING_NAME_MAP + ): + if errcheck: + warnings.warn( + "Unsupported coordinate operation: " + f"{self.coordinate_operation.method_name}" + ) + return {"crs_wkt": cf_dict["crs_wkt"]} + cf_dict.update( + _INVERSE_GEOGRAPHIC_GRID_MAPPING_NAME_MAP[ + self.coordinate_operation.method_name.lower() + ](self.coordinate_operation) + ) + else: + cf_dict["grid_mapping_name"] = "latitude_longitude" + return cf_dict + + # handle projected CRS + coordinate_operation = None + if not self.is_bound and self.is_projected: + coordinate_operation = self.coordinate_operation + cf_dict["projected_crs_name"] = self.name + coordinate_operation_name = ( + None + if not coordinate_operation + else coordinate_operation.method_name.lower().replace(" ", "_") + ) + if coordinate_operation_name not in _INVERSE_GRID_MAPPING_NAME_MAP: + if errcheck: + if coordinate_operation: + warnings.warn( + "Unsupported coordinate operation: " + f"{coordinate_operation.method_name}" + ) + else: + warnings.warn("Coordinate operation not found.") + + return {"crs_wkt": cf_dict["crs_wkt"]} + + cf_dict.update( + _INVERSE_GRID_MAPPING_NAME_MAP[coordinate_operation_name]( + coordinate_operation + ) + ) + return cf_dict
+ + +
+[docs] + @staticmethod + def from_cf( + in_cf: dict, + ellipsoidal_cs: Any | None = None, + cartesian_cs: Any | None = None, + vertical_cs: Any | None = None, + ) -> "CRS": + """ + .. versionadded:: 2.2.0 + + .. versionadded:: 3.0.0 ellipsoidal_cs, cartesian_cs, vertical_cs + + This converts a Climate and Forecast (CF) Grid Mapping Version 1.8 + dict to a :obj:`pyproj.crs.CRS` object. + + :ref:`build_crs_cf` + + Parameters + ---------- + in_cf: dict + CF version of the projection. + ellipsoidal_cs: Any, optional + Input to create an Ellipsoidal Coordinate System. + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or an Ellipsoidal Coordinate System created from :ref:`coordinate_system`. + cartesian_cs: Any, optional + Input to create a Cartesian Coordinate System. + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or :class:`pyproj.crs.coordinate_system.Cartesian2DCS`. + vertical_cs: Any, optional + Input to create a Vertical Coordinate System accepted by + :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or :class:`pyproj.crs.coordinate_system.VerticalCS` + + Returns + ------- + CRS + """ + # pylint: disable=too-many-branches + + unknown_names = ("unknown", "undefined") + if "crs_wkt" in in_cf: + return CRS(in_cf["crs_wkt"]) + if "spatial_ref" in in_cf: # for previous supported WKT key + return CRS(in_cf["spatial_ref"]) + + grid_mapping_name = in_cf.get("grid_mapping_name") + if grid_mapping_name is None: + raise CRSError("CF projection parameters missing 'grid_mapping_name'") + + # build datum if possible + datum = _horizontal_datum_from_params(in_cf) + + # build geographic CRS + try: + geographic_conversion_method: None | Callable = ( + _GEOGRAPHIC_GRID_MAPPING_NAME_MAP[grid_mapping_name] + ) + except KeyError: + geographic_conversion_method = None + + geographic_crs_name = in_cf.get("geographic_crs_name") + if datum: + geographic_crs: CRS = GeographicCRS( + name=geographic_crs_name or "undefined", + datum=datum, + ellipsoidal_cs=ellipsoidal_cs, + ) + elif geographic_crs_name and geographic_crs_name not in unknown_names: + geographic_crs = CRS(geographic_crs_name) + if ellipsoidal_cs is not None: + geographic_crs_json = geographic_crs.to_json_dict() + geographic_crs_json["coordinate_system"] = ( + CoordinateSystem.from_user_input(ellipsoidal_cs).to_json_dict() + ) + geographic_crs = CRS(geographic_crs_json) + else: + geographic_crs = GeographicCRS(ellipsoidal_cs=ellipsoidal_cs) + if grid_mapping_name == "latitude_longitude": + return geographic_crs + if geographic_conversion_method is not None: + return DerivedGeographicCRS( + base_crs=geographic_crs, + conversion=geographic_conversion_method(in_cf), + ellipsoidal_cs=ellipsoidal_cs, + ) + + # build projected CRS + try: + conversion_method = _GRID_MAPPING_NAME_MAP[grid_mapping_name] + except KeyError: + raise CRSError( + f"Unsupported grid mapping name: {grid_mapping_name}" + ) from None + projected_crs = ProjectedCRS( + name=in_cf.get("projected_crs_name", "undefined"), + conversion=conversion_method(in_cf), + geodetic_crs=geographic_crs, + cartesian_cs=cartesian_cs, + ) + + # build bound CRS if exists + bound_crs = None + if "towgs84" in in_cf: + bound_crs = BoundCRS( + source_crs=projected_crs, + target_crs="WGS 84", + transformation=ToWGS84Transformation( + projected_crs.geodetic_crs, *_try_list_if_string(in_cf["towgs84"]) + ), + ) + if "geopotential_datum_name" not in in_cf: + return bound_crs or projected_crs + + # build Vertical CRS + vertical_crs = VerticalCRS( + name="undefined", + datum=in_cf["geopotential_datum_name"], + geoid_model=in_cf.get("geoid_name"), + vertical_cs=vertical_cs, + ) + + # build compound CRS + return CompoundCRS( + name="undefined", components=[bound_crs or projected_crs, vertical_crs] + )
+ + +
+[docs] + def cs_to_cf(self) -> list[dict]: + """ + .. versionadded:: 3.0.0 + + This converts all coordinate systems (cs) in the CRS + to a list of Climate and Forecast (CF) Version 1.8 dicts. + + :ref:`build_crs_cf` + + Returns + ------- + list[dict]: + CF-1.8 version of the coordinate systems. + """ + cf_axis_list = [] + + def rotated_pole(crs): + try: + return ( + crs.coordinate_operation + and crs.coordinate_operation.method_name.lower() + in _INVERSE_GEOGRAPHIC_GRID_MAPPING_NAME_MAP + ) + except KeyError: + return False + + if self.type_name == "Temporal CRS" and self.datum: + datum_json = self.datum.to_json_dict() + origin = datum_json.get("time_origin", "1875-05-20").strip().rstrip("zZ") + if len(origin) == 4: + origin = f"{origin}-01-01" + axis = self.axis_info[0] + cf_temporal_axis = { + "standard_name": "time", + "long_name": "time", + "calendar": ( + datum_json.get("calendar", "proleptic_gregorian") + .lower() + .replace(" ", "_") + ), + "axis": "T", + } + unit_name = axis.unit_name.lower().replace("calendar", "").strip() + # no units for TemporalDateTime + if unit_name: + cf_temporal_axis["units"] = f"{unit_name} since {origin}" + cf_axis_list.append(cf_temporal_axis) + if self.coordinate_system: + cf_axis_list.extend( + self.coordinate_system.to_cf(rotated_pole=rotated_pole(self)) + ) + elif self.is_bound and self.source_crs and self.source_crs.coordinate_system: + cf_axis_list.extend( + self.source_crs.coordinate_system.to_cf( + rotated_pole=rotated_pole(self.source_crs) + ) + ) + else: + for sub_crs in self.sub_crs_list: + cf_axis_list.extend(sub_crs.cs_to_cf()) + return cf_axis_list
+ + +
+[docs] + def is_exact_same(self, other: Any) -> bool: + """ + Check if the CRS objects are the exact same. + + Parameters + ---------- + other: Any + Check if the other CRS is the exact same to this object. + If the other object is not a CRS, it will try to create one. + On Failure, it will return False. + + Returns + ------- + bool + """ + try: + other = CRS.from_user_input(other) + except CRSError: + return False + return self._crs.is_exact_same(other._crs)
+ + +
+[docs] + def equals(self, other: Any, ignore_axis_order: bool = False) -> bool: + """ + + .. versionadded:: 2.5.0 + + Check if the CRS objects are equivalent. + + Parameters + ---------- + other: Any + Check if the other object is equivalent to this object. + If the other object is not a CRS, it will try to create one. + On Failure, it will return False. + ignore_axis_order: bool, default=False + If True, it will compare the CRS class and ignore the axis order. + + Returns + ------- + bool + """ + try: + other = CRS.from_user_input(other) + except CRSError: + return False + return self._crs.equals(other._crs, ignore_axis_order=ignore_axis_order)
+ + + @property + def geodetic_crs(self) -> Optional["CRS"]: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + CRS: + The geodeticCRS / geographicCRS from the CRS. + + """ + return ( + None + if self._crs.geodetic_crs is None + else self.__class__(self._crs.geodetic_crs) + ) + + @property + def source_crs(self) -> Optional["CRS"]: + """ + The base CRS of a BoundCRS or a DerivedCRS/ProjectedCRS, + or the source CRS of a CoordinateOperation. + + Returns + ------- + CRS + """ + return ( + None + if self._crs.source_crs is None + else self.__class__(self._crs.source_crs) + ) + + @property + def target_crs(self) -> Optional["CRS"]: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + CRS: + The hub CRS of a BoundCRS or the target CRS of a CoordinateOperation. + + """ + return ( + None + if self._crs.target_crs is None + else self.__class__(self._crs.target_crs) + ) + + @property + def sub_crs_list(self) -> list["CRS"]: + """ + If the CRS is a compound CRS, it will return a list of sub CRS objects. + + Returns + ------- + list[CRS] + """ + return [self.__class__(sub_crs) for sub_crs in self._crs.sub_crs_list] + + @property + def utm_zone(self) -> str | None: + """ + .. versionadded:: 2.6.0 + + Finds the UTM zone in a Projected CRS, Bound CRS, or Compound CRS + + Returns + ------- + str | None: + The UTM zone number and letter if applicable. + """ + if self.is_bound and self.source_crs: + return self.source_crs.utm_zone + if self.sub_crs_list: + for sub_crs in self.sub_crs_list: + if sub_crs.utm_zone: + return sub_crs.utm_zone + elif ( + self.coordinate_operation + and "UTM ZONE" in self.coordinate_operation.name.upper() + ): + return self.coordinate_operation.name.upper().split("UTM ZONE ")[-1] + return None + + @property + def name(self) -> str: + """ + Returns + ------- + str: + The name of the CRS (from :cpp:func:`proj_get_name`). + """ + return self._crs.name + + @property + def type_name(self) -> str: + """ + Returns + ------- + str: + The name of the type of the CRS object. + """ + return self._crs.type_name + + @property + def axis_info(self) -> list[Axis]: + """ + Retrieves all relevant axis information in the CRS. + If it is a Bound CRS, it gets the axis list from the Source CRS. + If it is a Compound CRS, it gets the axis list from the Sub CRS list. + + Returns + ------- + list[Axis]: + The list of axis information. + """ + return self._crs.axis_info + + @property + def area_of_use(self) -> AreaOfUse | None: + """ + Returns + ------- + AreaOfUse: + The area of use object with associated attributes. + """ + return self._crs.area_of_use + + @property + def ellipsoid(self) -> Ellipsoid | None: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + Ellipsoid: + The ellipsoid object with associated attributes. + """ + return self._crs.ellipsoid + + @property + def prime_meridian(self) -> PrimeMeridian | None: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + PrimeMeridian: + The prime meridian object with associated attributes. + """ + return self._crs.prime_meridian + + @property + def datum(self) -> Datum | None: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + Datum + """ + return self._crs.datum + + @property + def coordinate_system(self) -> CoordinateSystem | None: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + CoordinateSystem + """ + return self._crs.coordinate_system + + @property + def coordinate_operation(self) -> CoordinateOperation | None: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + CoordinateOperation + """ + return self._crs.coordinate_operation + + @property + def remarks(self) -> str: + """ + .. versionadded:: 2.4.0 + + Returns + ------- + str: + Remarks about object. + """ + return self._crs.remarks + + @property + def scope(self) -> str: + """ + .. versionadded:: 2.4.0 + + Returns + ------- + str: + Scope of object. + """ + return self._crs.scope + +
+[docs] + def to_wkt( + self, + version: WktVersion | str = WktVersion.WKT2_2019, + pretty: bool = False, + output_axis_rule: bool | None = None, + ) -> str: + """ + Convert the projection to a WKT string. + + Version options: + - WKT2_2015 + - WKT2_2015_SIMPLIFIED + - WKT2_2019 + - WKT2_2019_SIMPLIFIED + - WKT1_GDAL + - WKT1_ESRI + + .. versionadded:: 3.6.0 output_axis_rule + + Parameters + ---------- + version: pyproj.enums.WktVersion, optional + The version of the WKT output. + Default is :attr:`pyproj.enums.WktVersion.WKT2_2019`. + pretty: bool, default=False + If True, it will set the output to be a multiline string. + output_axis_rule: bool, optional, default=None + If True, it will set the axis rule on any case. If false, never. + None for AUTO, that depends on the CRS and version. + + Returns + ------- + str + """ + wkt = self._crs.to_wkt( + version=version, pretty=pretty, output_axis_rule=output_axis_rule + ) + if wkt is None: + raise CRSError( + f"CRS cannot be converted to a WKT string of a '{version}' version. " + "Select a different version of a WKT string or edit your CRS." + ) + return wkt
+ + +
+[docs] + def to_json(self, pretty: bool = False, indentation: int = 2) -> str: + """ + .. versionadded:: 2.4.0 + + Convert the object to a JSON string. + + Parameters + ---------- + pretty: bool, default=False + If True, it will set the output to be a multiline string. + indentation: int, default=2 + If pretty is True, it will set the width of the indentation. + + Returns + ------- + str + """ + proj_json = self._crs.to_json(pretty=pretty, indentation=indentation) + if proj_json is None: + raise CRSError("CRS cannot be converted to a PROJ JSON string.") + return proj_json
+ + +
+[docs] + def to_json_dict(self) -> dict: + """ + .. versionadded:: 2.4.0 + + Convert the object to a JSON dictionary. + + Returns + ------- + dict + """ + return self._crs.to_json_dict()
+ + +
+[docs] + def to_proj4(self, version: ProjVersion | int = ProjVersion.PROJ_5) -> str: + """ + Convert the projection to a PROJ string. + + .. warning:: You will likely lose important projection + information when converting to a PROJ string from + another format. See: + https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems # noqa: E501 + + Parameters + ---------- + version: pyproj.enums.ProjVersion + The version of the PROJ string output. + Default is :attr:`pyproj.enums.ProjVersion.PROJ_4`. + + Returns + ------- + str + """ + proj = self._crs.to_proj4(version=version) + if proj is None: + raise CRSError("CRS cannot be converted to a PROJ string.") + return proj
+ + +
+[docs] + def to_epsg(self, min_confidence: int = 70) -> int | None: + """ + Return the EPSG code best matching the CRS + or None if it a match is not found. + + Example: + + >>> from pyproj import CRS + >>> ccs = CRS("EPSG:4328") + >>> ccs.to_epsg() + 4328 + + If the CRS is bound, you can attempt to get an epsg code from + the source CRS: + + >>> from pyproj import CRS + >>> ccs = CRS("+proj=geocent +datum=WGS84 +towgs84=0,0,0") + >>> ccs.to_epsg() + >>> ccs.source_crs.to_epsg() + 4978 + >>> ccs == CRS.from_epsg(4978) + False + + Parameters + ---------- + min_confidence: int, default=70 + A value between 0-100 where 100 is the most confident. + :ref:`min_confidence` + + + Returns + ------- + int | None: + The best matching EPSG code matching the confidence level. + """ + return self._crs.to_epsg(min_confidence=min_confidence)
+ + +
+[docs] + def to_authority(self, auth_name: str | None = None, min_confidence: int = 70): + """ + .. versionadded:: 2.2.0 + + Return the authority name and code best matching the CRS + or None if it a match is not found. + + Example: + + >>> from pyproj import CRS + >>> ccs = CRS("EPSG:4328") + >>> ccs.to_authority() + ('EPSG', '4328') + + If the CRS is bound, you can get an authority from + the source CRS: + + >>> from pyproj import CRS + >>> ccs = CRS("+proj=geocent +datum=WGS84 +towgs84=0,0,0") + >>> ccs.to_authority() + >>> ccs.source_crs.to_authority() + ('EPSG', '4978') + >>> ccs == CRS.from_authorty('EPSG', '4978') + False + + Parameters + ---------- + auth_name: str, optional + The name of the authority to filter by. + min_confidence: int, default=70 + A value between 0-100 where 100 is the most confident. + :ref:`min_confidence` + + Returns + ------- + tuple(str, str) or None: + The best matching (<auth_name>, <code>) for the confidence level. + """ + return self._crs.to_authority( + auth_name=auth_name, min_confidence=min_confidence + )
+ + +
+[docs] + def list_authority( + self, auth_name: str | None = None, min_confidence: int = 70 + ) -> list[AuthorityMatchInfo]: + """ + .. versionadded:: 3.2.0 + + Return the authority names and codes best matching the CRS. + + Example: + + >>> from pyproj import CRS + >>> ccs = CRS("EPSG:4328") + >>> ccs.list_authority() + [AuthorityMatchInfo(auth_name='EPSG', code='4326', confidence=100)] + + If the CRS is bound, you can get an authority from + the source CRS: + + >>> from pyproj import CRS + >>> ccs = CRS("+proj=geocent +datum=WGS84 +towgs84=0,0,0") + >>> ccs.list_authority() + [] + >>> ccs.source_crs.list_authority() + [AuthorityMatchInfo(auth_name='EPSG', code='4978', confidence=70)] + >>> ccs == CRS.from_authorty('EPSG', '4978') + False + + Parameters + ---------- + auth_name: str, optional + The name of the authority to filter by. + min_confidence: int, default=70 + A value between 0-100 where 100 is the most confident. + :ref:`min_confidence` + + Returns + ------- + list[AuthorityMatchInfo]: + List of authority matches for the CRS. + """ + return self._crs.list_authority( + auth_name=auth_name, min_confidence=min_confidence + )
+ + +
+[docs] + def to_3d(self, name: str | None = None) -> "CRS": + """ + .. versionadded:: 3.1.0 + + Convert the current CRS to the 3D version if it makes sense. + + New vertical axis attributes: + - ellipsoidal height + - oriented upwards + - metre units + + Parameters + ---------- + name: str, optional + CRS name. Defaults to use the name of the original CRS. + + Returns + ------- + CRS + """ + return self.__class__(self._crs.to_3d(name=name))
+ + +
+[docs] + def to_2d(self, name: str | None = None) -> "CRS": + """ + .. versionadded:: 3.6.0 + + Convert the current CRS to the 2D version if it makes sense. + + Parameters + ---------- + name: str, optional + CRS name. Defaults to use the name of the original CRS. + + Returns + ------- + CRS + """ + return self.__class__(self._crs.to_2d(name=name))
+ + + @property + def is_geographic(self) -> bool: + """ + This checks if the CRS is geographic. + It will check if it has a geographic CRS + in the sub CRS if it is a compound CRS and will check if + the source CRS is geographic if it is a bound CRS. + + Returns + ------- + bool: + True if the CRS is in geographic (lon/lat) coordinates. + """ + return self._crs.is_geographic + + @property + def is_projected(self) -> bool: + """ + This checks if the CRS is projected. + It will check if it has a projected CRS + in the sub CRS if it is a compound CRS and will check if + the source CRS is projected if it is a bound CRS. + + Returns + ------- + bool: + True if CRS is projected. + """ + return self._crs.is_projected + + @property + def is_vertical(self) -> bool: + """ + .. versionadded:: 2.2.0 + + This checks if the CRS is vertical. + It will check if it has a vertical CRS + in the sub CRS if it is a compound CRS and will check if + the source CRS is vertical if it is a bound CRS. + + Returns + ------- + bool: + True if CRS is vertical. + """ + return self._crs.is_vertical + + @property + def is_bound(self) -> bool: + """ + Returns + ------- + bool: + True if CRS is bound. + """ + return self._crs.is_bound + + @property + def is_compound(self) -> bool: + """ + .. versionadded:: 3.1.0 + + Returns + ------- + bool: + True if CRS is compound. + """ + return self._crs.is_compound + + @property + def is_engineering(self) -> bool: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + bool: + True if CRS is local/engineering. + """ + return self._crs.is_engineering + + @property + def is_geocentric(self) -> bool: + """ + This checks if the CRS is geocentric and + takes into account if the CRS is bound. + + Returns + ------- + bool: + True if CRS is in geocentric (x/y) coordinates. + """ + return self._crs.is_geocentric + + @property + def is_derived(self): + """ + .. versionadded:: 3.2.0 + + Returns + ------- + bool: + True if CRS is a Derived CRS. + """ + return self._crs.is_derived + + @property + def is_deprecated(self) -> bool: + """ + .. versionadded:: 3.7.0 + + Check if the CRS is deprecated + + Returns + ------- + bool + """ + return self._crs.is_deprecated + +
+[docs] + def get_non_deprecated(self) -> list["CRS"]: + """ + .. versionadded:: 3.7.0 + + Return a list of non-deprecated objects related to this. + + Returns + ------- + list[CRS] + """ + return self._crs.get_non_deprecated()
+ + + def __eq__(self, other: Any) -> bool: + return self.equals(other) + + def __getstate__(self) -> dict[str, str]: + return {"srs": self.srs} + + def __setstate__(self, state: dict[str, Any]): + self.__dict__.update(state) + self._local = CRSLocal() + + def __hash__(self) -> int: + return hash(self.to_wkt()) + + def __str__(self) -> str: + return self.srs + + def __repr__(self) -> str: + # get axis information + axis_info_list: list[str] = [] + for axis in self.axis_info: + axis_info_list.extend(["- ", str(axis), "\n"]) + axis_info_str = "".join(axis_info_list) + + # get coordinate system & sub CRS info + source_crs_repr = "" + sub_crs_repr = "" + if self.coordinate_system and self.coordinate_system.axis_list: + coordinate_system_name = str(self.coordinate_system) + elif self.is_bound and self.source_crs: + coordinate_system_name = str(self.source_crs.coordinate_system) + source_crs_repr = f"Source CRS: {self.source_crs.name}\n" + else: + coordinate_system_names = [] + sub_crs_repr_list = ["Sub CRS:\n"] + for sub_crs in self.sub_crs_list: + coordinate_system_names.append(str(sub_crs.coordinate_system)) + sub_crs_repr_list.extend(["- ", sub_crs.name, "\n"]) + coordinate_system_name = "|".join(coordinate_system_names) + sub_crs_repr = "".join(sub_crs_repr_list) + + # get coordinate operation repr + coordinate_operation = "" + if self.coordinate_operation: + coordinate_operation = "".join( + [ + "Coordinate Operation:\n", + "- name: ", + str(self.coordinate_operation), + "\n- method: ", + self.coordinate_operation.method_name, + "\n", + ] + ) + + # get SRS representation + srs_repr = self.to_string() + srs_repr = srs_repr if len(srs_repr) <= 50 else " ".join([srs_repr[:50], "..."]) + axis_info_str = axis_info_str or "- undefined\n" + return ( + f"<{self.type_name}: {srs_repr}>\n" + f"Name: {self.name}\n" + f"Axis Info [{coordinate_system_name or 'undefined'}]:\n" + f"{axis_info_str}" + "Area of Use:\n" + f"{self.area_of_use or '- undefined'}\n" + f"{coordinate_operation}" + f"Datum: {self.datum}\n" + f"- Ellipsoid: {self.ellipsoid or 'undefined'}\n" + f"- Prime Meridian: {self.prime_meridian or 'undefined'}\n" + f"{source_crs_repr}" + f"{sub_crs_repr}" + )
+ + + +
+[docs] +class CustomConstructorCRS(CRS): + """ + This class is a base class for CRS classes + that use a different constructor than the main CRS class. + + .. versionadded:: 3.2.0 + + See: https://github.com/pyproj4/pyproj/issues/847 + """ + + @property + def _expected_types(self) -> tuple[str, ...]: + """ + These are the type names of the CRS class + that are expected when using the from_* methods. + """ + raise NotImplementedError + + def _check_type(self): + """ + This validates that the type of the CRS is expected + when using the from_* methods. + """ + if self.type_name not in self._expected_types: + raise CRSError( + f"Invalid type {self.type_name}. Expected {self._expected_types}." + ) + +
+[docs] + @classmethod + def from_user_input(cls, value: Any, **kwargs) -> "CRS": + """ + Initialize a CRS class instance with: + - PROJ string + - Dictionary of PROJ parameters + - PROJ keyword arguments for parameters + - JSON string with PROJ parameters + - CRS WKT string + - An authority string [i.e. 'epsg:4326'] + - An EPSG integer code [i.e. 4326] + - A tuple of ("auth_name": "auth_code") [i.e ('epsg', '4326')] + - An object with a `to_wkt` method. + - A :class:`pyproj.crs.CRS` class + + Parameters + ---------- + value : obj + A Python int, dict, or str. + + Returns + ------- + CRS + """ + if isinstance(value, cls): + return value + crs = cls.__new__(cls) + super(CustomConstructorCRS, crs).__init__(value, **kwargs) + crs._check_type() + return crs
+ + + @property + def geodetic_crs(self) -> Optional["CRS"]: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + CRS: + The geodeticCRS / geographicCRS from the CRS. + + """ + return None if self._crs.geodetic_crs is None else CRS(self._crs.geodetic_crs) + + @property + def source_crs(self) -> Optional["CRS"]: + """ + The base CRS of a BoundCRS or a DerivedCRS/ProjectedCRS, + or the source CRS of a CoordinateOperation. + + Returns + ------- + CRS + """ + return None if self._crs.source_crs is None else CRS(self._crs.source_crs) + + @property + def target_crs(self) -> Optional["CRS"]: + """ + .. versionadded:: 2.2.0 + + Returns + ------- + CRS: + The hub CRS of a BoundCRS or the target CRS of a CoordinateOperation. + + """ + return None if self._crs.target_crs is None else CRS(self._crs.target_crs) + + @property + def sub_crs_list(self) -> list["CRS"]: + """ + If the CRS is a compound CRS, it will return a list of sub CRS objects. + + Returns + ------- + list[CRS] + """ + return [CRS(sub_crs) for sub_crs in self._crs.sub_crs_list] + +
+[docs] + def to_3d(self, name: str | None = None) -> "CRS": + """ + .. versionadded:: 3.1.0 + + Convert the current CRS to the 3D version if it makes sense. + + New vertical axis attributes: + - ellipsoidal height + - oriented upwards + - metre units + + Parameters + ---------- + name: str, optional + CRS name. Defaults to use the name of the original CRS. + + Returns + ------- + CRS + """ + return CRS(self._crs.to_3d(name=name))
+
+ + + +
+[docs] +class GeographicCRS(CustomConstructorCRS): + """ + .. versionadded:: 2.5.0 + + This class is for building a Geographic CRS + """ + + _expected_types = ("Geographic CRS", "Geographic 2D CRS", "Geographic 3D CRS") + +
+[docs] + def __init__( + self, + name: str = "undefined", + datum: Any = "urn:ogc:def:ensemble:EPSG::6326", + ellipsoidal_cs: Any | None = None, + ) -> None: + """ + Parameters + ---------- + name: str, default="undefined" + Name of the CRS. + datum: Any, default="urn:ogc:def:ensemble:EPSG::6326" + Anything accepted by :meth:`pyproj.crs.Datum.from_user_input` or + a :class:`pyproj.crs.datum.CustomDatum`. + ellipsoidal_cs: Any, optional + Input to create an Ellipsoidal Coordinate System. + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or an Ellipsoidal Coordinate System created from :ref:`coordinate_system`. + """ + datum = Datum.from_user_input(datum).to_json_dict() + geographic_crs_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "GeographicCRS", + "name": name, + "coordinate_system": CoordinateSystem.from_user_input( + ellipsoidal_cs or Ellipsoidal2DCS() + ).to_json_dict(), + } + if datum["type"] == "DatumEnsemble": + geographic_crs_json["datum_ensemble"] = datum + else: + geographic_crs_json["datum"] = datum + super().__init__(geographic_crs_json)
+
+ + + +
+[docs] +class DerivedGeographicCRS(CustomConstructorCRS): + """ + .. versionadded:: 2.5.0 + + This class is for building a Derived Geographic CRS + """ + + _expected_types = ( + "Derived Geographic CRS", + "Derived Geographic 2D CRS", + "Derived Geographic 3D CRS", + ) + +
+[docs] + def __init__( + self, + base_crs: Any, + conversion: Any, + ellipsoidal_cs: Any | None = None, + name: str = "undefined", + ) -> None: + """ + Parameters + ---------- + base_crs: Any + Input to create the Geodetic CRS, a :class:`GeographicCRS` or + anything accepted by :meth:`pyproj.crs.CRS.from_user_input`. + conversion: Any + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or a conversion from :ref:`coordinate_operation`. + ellipsoidal_cs: Any, optional + Input to create an Ellipsoidal Coordinate System. + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or an Ellipsoidal Coordinate System created from :ref:`coordinate_system`. + name: str, default="undefined" + Name of the CRS. + """ + derived_geographic_crs_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "DerivedGeographicCRS", + "name": name, + "base_crs": CRS.from_user_input(base_crs).to_json_dict(), + "conversion": CoordinateOperation.from_user_input( + conversion + ).to_json_dict(), + "coordinate_system": CoordinateSystem.from_user_input( + ellipsoidal_cs or Ellipsoidal2DCS() + ).to_json_dict(), + } + super().__init__(derived_geographic_crs_json)
+
+ + + +
+[docs] +class GeocentricCRS(CustomConstructorCRS): + """ + .. versionadded:: 3.2.0 + + This class is for building a Geocentric CRS + """ + + _expected_types = ("Geocentric CRS",) + +
+[docs] + def __init__( + self, + name: str = "undefined", + datum: Any = "urn:ogc:def:datum:EPSG::6326", + ) -> None: + """ + Parameters + ---------- + name: str, default="undefined" + Name of the CRS. + datum: Any, default="urn:ogc:def:datum:EPSG::6326" + Anything accepted by :meth:`pyproj.crs.Datum.from_user_input` or + a :class:`pyproj.crs.datum.CustomDatum`. + """ + geocentric_crs_json = { + "$schema": ("https://proj.org/schemas/v0.2/projjson.schema.json"), + "type": "GeodeticCRS", + "name": name, + "datum": Datum.from_user_input(datum).to_json_dict(), + "coordinate_system": { + "subtype": "Cartesian", + "axis": [ + { + "name": "Geocentric X", + "abbreviation": "X", + "direction": "geocentricX", + "unit": "metre", + }, + { + "name": "Geocentric Y", + "abbreviation": "Y", + "direction": "geocentricY", + "unit": "metre", + }, + { + "name": "Geocentric Z", + "abbreviation": "Z", + "direction": "geocentricZ", + "unit": "metre", + }, + ], + }, + } + super().__init__(geocentric_crs_json)
+
+ + + +
+[docs] +class ProjectedCRS(CustomConstructorCRS): + """ + .. versionadded:: 2.5.0 + + This class is for building a Projected CRS. + """ + + _expected_types = ("Projected CRS", "Derived Projected CRS") + +
+[docs] + def __init__( + self, + conversion: Any, + name: str = "undefined", + cartesian_cs: Any | None = None, + geodetic_crs: Any | None = None, + ) -> None: + """ + Parameters + ---------- + conversion: Any + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or a conversion from :ref:`coordinate_operation`. + name: str, optional + The name of the Projected CRS. Default is undefined. + cartesian_cs: Any, optional + Input to create a Cartesian Coordinate System. + Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or :class:`pyproj.crs.coordinate_system.Cartesian2DCS`. + geodetic_crs: Any, optional + Input to create the Geodetic CRS, a :class:`GeographicCRS` or + anything accepted by :meth:`pyproj.crs.CRS.from_user_input`. + """ + proj_crs_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "ProjectedCRS", + "name": name, + "base_crs": CRS.from_user_input( + geodetic_crs or GeographicCRS() + ).to_json_dict(), + "conversion": CoordinateOperation.from_user_input( + conversion + ).to_json_dict(), + "coordinate_system": CoordinateSystem.from_user_input( + cartesian_cs or Cartesian2DCS() + ).to_json_dict(), + } + super().__init__(proj_crs_json)
+
+ + + +
+[docs] +class VerticalCRS(CustomConstructorCRS): + """ + .. versionadded:: 2.5.0 + + This class is for building a Vertical CRS. + + .. warning:: geoid_model support only exists in PROJ >= 6.3.0 + + """ + + _expected_types = ("Vertical CRS",) + +
+[docs] + def __init__( + self, + name: str, + datum: Any, + vertical_cs: Any | None = None, + geoid_model: str | None = None, + ) -> None: + """ + Parameters + ---------- + name: str + The name of the Vertical CRS (e.g. NAVD88 height). + datum: Any + Anything accepted by :meth:`pyproj.crs.Datum.from_user_input` + vertical_cs: Any, optional + Input to create a Vertical Coordinate System accepted by + :meth:`pyproj.crs.CoordinateSystem.from_user_input` + or :class:`pyproj.crs.coordinate_system.VerticalCS` + geoid_model: str, optional + The name of the GEOID Model (e.g. GEOID12B). + """ + vert_crs_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "VerticalCRS", + "name": name, + "datum": Datum.from_user_input(datum).to_json_dict(), + "coordinate_system": CoordinateSystem.from_user_input( + vertical_cs or VerticalCS() + ).to_json_dict(), + } + if geoid_model is not None: + vert_crs_json["geoid_model"] = {"name": geoid_model} + + super().__init__(vert_crs_json)
+
+ + + +
+[docs] +class CompoundCRS(CustomConstructorCRS): + """ + .. versionadded:: 2.5.0 + + This class is for building a Compound CRS. + """ + + _expected_types = ("Compound CRS",) + +
+[docs] + def __init__(self, name: str, components: list[Any]) -> None: + """ + Parameters + ---------- + name: str + The name of the Compound CRS. + components: list[Any], optional + List of CRS to create a Compound Coordinate System. + List of anything accepted by :meth:`pyproj.crs.CRS.from_user_input` + """ + compound_crs_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "CompoundCRS", + "name": name, + "components": [ + CRS.from_user_input(component).to_json_dict() + for component in components + ], + } + + super().__init__(compound_crs_json)
+
+ + + +
+[docs] +class BoundCRS(CustomConstructorCRS): + """ + .. versionadded:: 2.5.0 + + This class is for building a Bound CRS. + """ + + _expected_types = ("Bound CRS",) + +
+[docs] + def __init__(self, source_crs: Any, target_crs: Any, transformation: Any) -> None: + """ + Parameters + ---------- + source_crs: Any + Input to create a source CRS. + target_crs: Any + Input to create the target CRS. + transformation: Any + Input to create the transformation. + """ + bound_crs_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "BoundCRS", + "source_crs": CRS.from_user_input(source_crs).to_json_dict(), + "target_crs": CRS.from_user_input(target_crs).to_json_dict(), + "transformation": CoordinateOperation.from_user_input( + transformation + ).to_json_dict(), + } + + super().__init__(bound_crs_json)
+
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/crs/datum.html b/3.7.0/_modules/pyproj/crs/datum.html new file mode 100644 index 000000000..0c152c763 --- /dev/null +++ b/3.7.0/_modules/pyproj/crs/datum.html @@ -0,0 +1,448 @@ + + + + + + + + pyproj.crs.datum - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.crs.datum

+"""
+This module is for building datums to be used when
+building a CRS.
+"""
+
+from typing import Any
+
+from pyproj._crs import Datum, Ellipsoid, PrimeMeridian
+
+
+
+[docs] +class CustomDatum(Datum): + """ + .. versionadded:: 2.5.0 + + Class to build a datum based on an ellipsoid and prime meridian. + """ + +
+[docs] + def __new__( + cls, + name: str = "undefined", + ellipsoid: Any = "WGS 84", + prime_meridian: Any = "Greenwich", + ): + """ + Parameters + ---------- + name: str, default="undefined" + Name of the datum. + ellipsoid: Any, default="WGS 84" + Anything accepted by :meth:`pyproj.crs.Ellipsoid.from_user_input` + or a :class:`pyproj.crs.datum.CustomEllipsoid`. + prime_meridian: Any, default="Greenwich" + Anything accepted by :meth:`pyproj.crs.PrimeMeridian.from_user_input`. + """ + datum_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "GeodeticReferenceFrame", + "name": name, + "ellipsoid": Ellipsoid.from_user_input(ellipsoid).to_json_dict(), + "prime_meridian": PrimeMeridian.from_user_input( + prime_meridian + ).to_json_dict(), + } + return cls.from_json_dict(datum_json)
+
+ + + +
+[docs] +class CustomEllipsoid(Ellipsoid): + """ + .. versionadded:: 2.5.0 + + Class to build a custom ellipsoid. + """ + +
+[docs] + def __new__( + cls, + name: str = "undefined", + semi_major_axis: float | None = None, + inverse_flattening: float | None = None, + semi_minor_axis: float | None = None, + radius: float | None = None, + ): + """ + Parameters + ---------- + name: str, default="undefined" + Name of the ellipsoid. + semi_major_axis: float, optional + The semi major axis in meters. Required if missing radius. + inverse_flattening: float, optional + The inverse flattening in meters. + Required if missing semi_minor_axis and radius. + semi_minor_axis: float, optional + The semi minor axis in meters. + Required if missing inverse_flattening and radius. + radius: float, optional + The radius in meters. Can only be used alone. + Cannot be mixed with other parameters. + """ + ellipsoid_json: dict[str, float | str] = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "Ellipsoid", + "name": name, + } + if semi_major_axis is not None: + ellipsoid_json["semi_major_axis"] = semi_major_axis + if inverse_flattening is not None: + ellipsoid_json["inverse_flattening"] = inverse_flattening + if semi_minor_axis is not None: + ellipsoid_json["semi_minor_axis"] = semi_minor_axis + if radius is not None: + ellipsoid_json["radius"] = radius + return cls.from_json_dict(ellipsoid_json)
+
+ + + +
+[docs] +class CustomPrimeMeridian(PrimeMeridian): + """ + .. versionadded:: 2.5.0 + + Class to build a prime meridian based on a longitude. + """ + +
+[docs] + def __new__(cls, longitude: float, name: str = "undefined"): + """ + Parameters + ---------- + longitude: float + Longitude of prime meridian. + name: str, optional + Name of the prime meridian. + """ + datum_json = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "PrimeMeridian", + "name": name, + "longitude": longitude, + } + return cls.from_json_dict(datum_json)
+
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/crs/enums.html b/3.7.0/_modules/pyproj/crs/enums.html new file mode 100644 index 000000000..382b89261 --- /dev/null +++ b/3.7.0/_modules/pyproj/crs/enums.html @@ -0,0 +1,475 @@ + + + + + + + + pyproj.crs.enums - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.crs.enums

+"""
+This module contains enumerations used in pyproj.crs.
+"""
+
+from pyproj.enums import BaseEnum
+
+
+
+[docs] +class DatumType(BaseEnum): + """ + .. versionadded:: 2.5.0 + + Datum Types for creating datum with :meth:`pyproj.crs.Datum.from_name` + + Attributes + ---------- + GEODETIC_REFERENCE_FRAME + DYNAMIC_GEODETIC_REFERENCE_FRAME + VERTICAL_REFERENCE_FRAME + DYNAMIC_VERTICAL_REFERENCE_FRAME + DATUM_ENSEMBLE + """ + + GEODETIC_REFERENCE_FRAME = "GEODETIC_REFERENCE_FRAME" + DYNAMIC_GEODETIC_REFERENCE_FRAME = "DYNAMIC_GEODETIC_REFERENCE_FRAME" + VERTICAL_REFERENCE_FRAME = "VERTICAL_REFERENCE_FRAME" + DYNAMIC_VERTICAL_REFERENCE_FRAME = "DYNAMIC_VERTICAL_REFERENCE_FRAME" + DATUM_ENSEMBLE = "DATUM_ENSEMBLE"
+ + + +
+[docs] +class CoordinateOperationType(BaseEnum): + """ + .. versionadded:: 2.5.0 + + Coordinate Operation Types for creating operation + with :meth:`pyproj.crs.CoordinateOperation.from_name` + + Attributes + ---------- + CONVERSION + TRANSFORMATION + CONCATENATED_OPERATION + OTHER_COORDINATE_OPERATION + """ + + CONVERSION = "CONVERSION" + TRANSFORMATION = "TRANSFORMATION" + CONCATENATED_OPERATION = "CONCATENATED_OPERATION" + OTHER_COORDINATE_OPERATION = "OTHER_COORDINATE_OPERATION"
+ + + +
+[docs] +class Cartesian2DCSAxis(BaseEnum): + """ + .. versionadded:: 2.5.0 + + Cartesian 2D Coordinate System Axis for creating axis with + with :class:`pyproj.crs.coordinate_system.Cartesian2DCS` + + Attributes + ---------- + EASTING_NORTHING + NORTHING_EASTING + EASTING_NORTHING_FT + NORTHING_EASTING_FT + EASTING_NORTHING_US_FT + NORTHING_EASTING_US_FT + NORTH_POLE_EASTING_SOUTH_NORTHING_SOUTH + SOUTH_POLE_EASTING_NORTH_NORTHING_NORTH + WESTING_SOUTHING + """ + + EASTING_NORTHING = "EASTING_NORTHING" + NORTHING_EASTING = "NORTHING_EASTING" + EASTING_NORTHING_FT = "EASTING_NORTHING_FT" + NORTHING_EASTING_FT = "NORTHING_EASTING_FT" + EASTING_NORTHING_US_FT = "EASTING_NORTHING_US_FT" + NORTHING_EASTING_US_FT = "NORTHING_EASTING_US_FT" + NORTH_POLE_EASTING_SOUTH_NORTHING_SOUTH = "NORTH_POLE_EASTING_SOUTH_NORTHING_SOUTH" + SOUTH_POLE_EASTING_NORTH_NORTHING_NORTH = "SOUTH_POLE_EASTING_NORTH_NORTHING_NORTH" + WESTING_SOUTHING = "WESTING_SOUTHING"
+ + + +
+[docs] +class Ellipsoidal2DCSAxis(BaseEnum): + """ + .. versionadded:: 2.5.0 + + Ellipsoidal 2D Coordinate System Axis for creating axis with + with :class:`pyproj.crs.coordinate_system.Ellipsoidal2DCS` + + Attributes + ---------- + LONGITUDE_LATITUDE + LATITUDE_LONGITUDE + """ + + LONGITUDE_LATITUDE = "LONGITUDE_LATITUDE" + LATITUDE_LONGITUDE = "LATITUDE_LONGITUDE"
+ + + +
+[docs] +class Ellipsoidal3DCSAxis(BaseEnum): + """ + .. versionadded:: 2.5.0 + + Ellipsoidal 3D Coordinate System Axis for creating axis with + with :class:`pyproj.crs.coordinate_system.Ellipsoidal3DCS` + + Attributes + ---------- + LONGITUDE_LATITUDE_HEIGHT + LATITUDE_LONGITUDE_HEIGHT + """ + + LONGITUDE_LATITUDE_HEIGHT = "LONGITUDE_LATITUDE_HEIGHT" + LATITUDE_LONGITUDE_HEIGHT = "LATITUDE_LONGITUDE_HEIGHT"
+ + + +
+[docs] +class VerticalCSAxis(BaseEnum): + """ + .. versionadded:: 2.5.0 + + Vertical Coordinate System Axis for creating axis with + with :class:`pyproj.crs.coordinate_system.VerticalCS` + + Attributes + ---------- + UP + UP_FT + UP_US_FT + DEPTH + DEPTH_FT + DEPTH_US_FT + GRAVITY_HEIGHT + GRAVITY_HEIGHT_FT + GRAVITY_HEIGHT_US_FT + """ + + GRAVITY_HEIGHT = "GRAVITY_HEIGHT" + GRAVITY_HEIGHT_FT = "GRAVITY_HEIGHT_FT" + GRAVITY_HEIGHT_US_FT = "GRAVITY_HEIGHT_US_FT" + DEPTH = "DEPTH" + DEPTH_FT = "DEPTH_FT" + DEPTH_US_FT = "DEPTH_US_FT" + UP = "UP" + UP_FT = "UP_FT" + UP_US_FT = "UP_US_FT"
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/datadir.html b/3.7.0/_modules/pyproj/datadir.html new file mode 100644 index 000000000..43df6f6dc --- /dev/null +++ b/3.7.0/_modules/pyproj/datadir.html @@ -0,0 +1,442 @@ + + + + + + + + pyproj.datadir - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.datadir

+"""
+Module for managing the PROJ data directory.
+"""
+
+# pylint: disable=global-statement
+import os
+import shutil
+import sys
+from pathlib import Path
+
+from pyproj._context import (  # noqa: F401  pylint: disable=unused-import
+    _set_context_data_dir,
+    get_user_data_dir,
+)
+from pyproj.exceptions import DataDirError
+
+_USER_PROJ_DATA = None
+_VALIDATED_PROJ_DATA = None
+
+
+
+[docs] +def set_data_dir(proj_data_dir: str | Path) -> None: + """ + Set the data directory for PROJ to use. + + Parameters + ---------- + proj_data_dir: str | Path + The path to the PROJ data directory. + """ + global _USER_PROJ_DATA + global _VALIDATED_PROJ_DATA + _USER_PROJ_DATA = str(proj_data_dir) + # set to none to re-validate + _VALIDATED_PROJ_DATA = None + # need to reset the global PROJ context + # to prevent core dumping if the data directory + # is not found. + _set_context_data_dir()
+ + + +
+[docs] +def append_data_dir(proj_data_dir: str | Path) -> None: + """ + Add an additional data directory for PROJ to use. + + Parameters + ---------- + proj_data_dir: str | Path + The path to the PROJ data directory. + """ + set_data_dir(os.pathsep.join([get_data_dir(), str(proj_data_dir)]))
+ + + +
+[docs] +def get_data_dir() -> str: + """ + The order of preference for the data directory is: + + 1. The one set by pyproj.datadir.set_data_dir (if exists & valid) + 2. The internal proj directory (if exists & valid) + 3. The directory in PROJ_DATA (PROJ 9.1+) | PROJ_LIB (PROJ<9.1) (if exists & valid) + 4. The directory on sys.prefix (if exists & valid) + 5. The directory on the PATH (if exists & valid) + + Returns + ------- + str: + The valid data directory. + + """ + # to avoid re-validating + global _VALIDATED_PROJ_DATA + if _VALIDATED_PROJ_DATA is not None: + return _VALIDATED_PROJ_DATA + internal_datadir = Path(__file__).absolute().parent / "proj_dir" / "share" / "proj" + proj_lib_dirs = os.environ.get("PROJ_DATA", os.environ.get("PROJ_LIB", "")) + prefix_datadir = Path(sys.prefix, "share", "proj") + conda_windows_prefix_datadir = Path(sys.prefix, "Library", "share", "proj") + + def valid_data_dir(potential_data_dir): + if ( + potential_data_dir is not None + and Path(potential_data_dir, "proj.db").exists() + ): + return True + return False + + def valid_data_dirs(potential_data_dirs): + if potential_data_dirs is None: + return False + for proj_data_dir in potential_data_dirs.split(os.pathsep): + if valid_data_dir(proj_data_dir): + return True + return None + + if valid_data_dirs(_USER_PROJ_DATA): + _VALIDATED_PROJ_DATA = _USER_PROJ_DATA + elif valid_data_dir(internal_datadir): + _VALIDATED_PROJ_DATA = str(internal_datadir) + elif valid_data_dirs(proj_lib_dirs): + _VALIDATED_PROJ_DATA = proj_lib_dirs + elif valid_data_dir(prefix_datadir): + _VALIDATED_PROJ_DATA = str(prefix_datadir) + elif valid_data_dir(conda_windows_prefix_datadir): + _VALIDATED_PROJ_DATA = str(conda_windows_prefix_datadir) + else: + proj_exe = shutil.which("proj", path=sys.prefix) + if proj_exe is None: + proj_exe = shutil.which("proj") + if proj_exe is not None: + system_proj_dir = Path(proj_exe).parent.parent / "share" / "proj" + if valid_data_dir(system_proj_dir): + _VALIDATED_PROJ_DATA = str(system_proj_dir) + + if _VALIDATED_PROJ_DATA is None: + raise DataDirError( + "Valid PROJ data directory not found. " + "Either set the path using the environmental variable " + "PROJ_DATA (PROJ 9.1+) | PROJ_LIB (PROJ<9.1) or " + "with `pyproj.datadir.set_data_dir`." + ) + return _VALIDATED_PROJ_DATA
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/enums.html b/3.7.0/_modules/pyproj/enums.html new file mode 100644 index 000000000..38ce596b0 --- /dev/null +++ b/3.7.0/_modules/pyproj/enums.html @@ -0,0 +1,501 @@ + + + + + + + + pyproj.enums - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.enums

+"""
+This module contains enumerations used in pyproj.
+"""
+
+from enum import Enum, IntFlag
+
+
+class BaseEnum(Enum):
+    """
+    Base enumeration class that handles
+    input as strings ignoring case.
+    """
+
+    @classmethod
+    def create(cls, item):
+        """
+        Handles finding the enumeration
+        ignoring case if provided as a string.
+        """
+        try:
+            return cls(item)
+        except ValueError:
+            pass
+        if isinstance(item, str):
+            item = item.upper()
+        for member in cls:
+            if member.value == item:
+                return member
+        raise ValueError(
+            f"Invalid value supplied '{item}'. "
+            f"Only {tuple(version.value for version in cls)} are supported."
+        )
+
+
+
+[docs] +class WktVersion(BaseEnum): + """ + .. versionadded:: 2.2.0 + + Supported CRS WKT string versions + + See: :c:enum:`PJ_WKT_TYPE` + """ + + #: WKT Version 2 from 2015 + WKT2_2015 = "WKT2_2015" + #: WKT Version 2 from 2015 Simplified + WKT2_2015_SIMPLIFIED = "WKT2_2015_SIMPLIFIED" + #: Deprecated alias for WKT Version 2 from 2019 + WKT2_2018 = "WKT2_2018" + #: Deprecated alias for WKT Version 2 from 2019 Simplified + WKT2_2018_SIMPLIFIED = "WKT2_2018_SIMPLIFIED" + #: WKT Version 2 from 2019 + WKT2_2019 = "WKT2_2019" + #: WKT Version 2 from 2019 Simplified + WKT2_2019_SIMPLIFIED = "WKT2_2019_SIMPLIFIED" + #: WKT Version 1 GDAL Style + WKT1_GDAL = "WKT1_GDAL" + #: WKT Version 1 ESRI Style + WKT1_ESRI = "WKT1_ESRI"
+ + + +
+[docs] +class ProjVersion(BaseEnum): + """ + .. versionadded:: 2.2.0 + + Supported CRS PROJ string versions + """ + + #: PROJ String version 4 + PROJ_4 = 4 + #: PROJ String version 5 + PROJ_5 = 5
+ + + +
+[docs] +class TransformDirection(BaseEnum): + """ + .. versionadded:: 2.2.0 + + Supported transform directions + """ + + #: Forward direction + FORWARD = "FORWARD" + #: Inverse direction + INVERSE = "INVERSE" + #: Do nothing + IDENT = "IDENT"
+ + + +
+[docs] +class PJType(BaseEnum): + """ + .. versionadded:: 2.4.0 + + PJ Types for listing codes with :func:`pyproj.get_codes` + + See: :c:enum:`PJ_TYPE` + + Attributes + ---------- + UNKNOWN + ELLIPSOID + PRIME_MERIDIAN + GEODETIC_REFERENCE_FRAME + DYNAMIC_GEODETIC_REFERENCE_FRAME + VERTICAL_REFERENCE_FRAME + DYNAMIC_VERTICAL_REFERENCE_FRAME + DATUM_ENSEMBLE + CRS + GEODETIC_CRS + GEOCENTRIC_CRS + GEOGRAPHIC_CRS + GEOGRAPHIC_2D_CRS + GEOGRAPHIC_3D_CRS + VERTICAL_CRS + PROJECTED_CRS + COMPOUND_CRS + TEMPORAL_CRS + ENGINEERING_CRS + BOUND_CRS + OTHER_CRS + CONVERSION + TRANSFORMATION + CONCATENATED_OPERATION + OTHER_COORDINATE_OPERATION + + """ + + UNKNOWN = "UNKNOWN" + ELLIPSOID = "ELLIPSOID" + PRIME_MERIDIAN = "PRIME_MERIDIAN" + GEODETIC_REFERENCE_FRAME = "GEODETIC_REFERENCE_FRAME" + DYNAMIC_GEODETIC_REFERENCE_FRAME = "DYNAMIC_GEODETIC_REFERENCE_FRAME" + VERTICAL_REFERENCE_FRAME = "VERTICAL_REFERENCE_FRAME" + DYNAMIC_VERTICAL_REFERENCE_FRAME = "DYNAMIC_VERTICAL_REFERENCE_FRAME" + DATUM_ENSEMBLE = "DATUM_ENSEMBLE" + CRS = "CRS" + GEODETIC_CRS = "GEODETIC_CRS" + GEOCENTRIC_CRS = "GEOCENTRIC_CRS" + GEOGRAPHIC_CRS = "GEOGRAPHIC_CRS" + GEOGRAPHIC_2D_CRS = "GEOGRAPHIC_2D_CRS" + GEOGRAPHIC_3D_CRS = "GEOGRAPHIC_3D_CRS" + VERTICAL_CRS = "VERTICAL_CRS" + PROJECTED_CRS = "PROJECTED_CRS" + DERIVED_PROJECTED_CRS = "DERIVED_PROJECTED_CRS" + COMPOUND_CRS = "COMPOUND_CRS" + TEMPORAL_CRS = "TEMPORAL_CRS" + ENGINEERING_CRS = "ENGINEERING_CRS" + BOUND_CRS = "BOUND_CRS" + OTHER_CRS = "OTHER_CRS" + CONVERSION = "CONVERSION" + TRANSFORMATION = "TRANSFORMATION" + CONCATENATED_OPERATION = "CONCATENATED_OPERATION" + OTHER_COORDINATE_OPERATION = "OTHER_COORDINATE_OPERATION"
+ + + +
+[docs] +class GeodIntermediateFlag(IntFlag): + """ + .. versionadded:: 3.1.0 + + Flags to be used in Geod.[inv|fwd]_intermediate() + """ + + DEFAULT = 0x0 + + NPTS_ROUND = 0x0 + NPTS_CEIL = 0x1 + NPTS_TRUNC = 0x2 + + DEL_S_RECALC = 0x00 + DEL_S_NO_RECALC = 0x10 + + AZIS_DISCARD = 0x000 + AZIS_KEEP = 0x100
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/exceptions.html b/3.7.0/_modules/pyproj/exceptions.html new file mode 100644 index 000000000..f58f9474c --- /dev/null +++ b/3.7.0/_modules/pyproj/exceptions.html @@ -0,0 +1,353 @@ + + + + + + + + pyproj.exceptions - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.exceptions

+"""
+Exceptions for pyproj
+"""
+
+from pyproj._context import _clear_proj_error, _get_proj_error
+
+
+
+[docs] +class ProjError(RuntimeError): + """Raised when a Proj error occurs.""" + + def __init__(self, error_message: str) -> None: + proj_error = _get_proj_error() + if proj_error is not None: + error_message = f"{error_message}: (Internal Proj Error: {proj_error})" + _clear_proj_error() + super().__init__(error_message)
+ + + +
+[docs] +class CRSError(ProjError): + """Raised when a CRS error occurs."""
+ + + +
+[docs] +class GeodError(RuntimeError): + """Raised when a Geod error occurs."""
+ + + +
+[docs] +class DataDirError(RuntimeError): + """Raised when a the data directory was not found."""
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/geod.html b/3.7.0/_modules/pyproj/geod.html new file mode 100644 index 000000000..5a6062e8c --- /dev/null +++ b/3.7.0/_modules/pyproj/geod.html @@ -0,0 +1,1529 @@ + + + + + + + + pyproj.geod - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.geod

+"""
+The Geod class can perform forward and inverse geodetic, or
+Great Circle, computations.  The forward computation involves
+determining latitude, longitude and back azimuth of a terminus
+point given the latitude and longitude of an initial point, plus
+azimuth and distance. The inverse computation involves
+determining the forward and back azimuths and distance given the
+latitudes and longitudes of an initial and terminus point.
+"""
+
+__all__ = [
+    "Geod",
+    "pj_ellps",
+    "geodesic_version_str",
+    "GeodIntermediateFlag",
+    "GeodIntermediateReturn",
+    "reverse_azimuth",
+]
+
+import math
+import warnings
+from typing import Any
+
+from pyproj._geod import Geod as _Geod
+from pyproj._geod import GeodIntermediateReturn, geodesic_version_str
+from pyproj._geod import reverse_azimuth as _reverse_azimuth
+from pyproj.enums import GeodIntermediateFlag
+from pyproj.exceptions import GeodError
+from pyproj.list import get_ellps_map
+from pyproj.utils import DataType, _convertback, _copytobuffer
+
+pj_ellps = get_ellps_map()
+
+
+def _params_from_ellps_map(ellps: str) -> tuple[float, float, float, float, bool]:
+    """
+    Build Geodesic parameters from PROJ ellips map
+
+    Parameter
+    ---------
+    ellps: str
+        The name of the ellipse in the map.
+
+    Returns
+    -------
+    tuple[float, float, float, float, bool]
+
+    """
+    ellps_dict = pj_ellps[ellps]
+    semi_major_axis, semi_minor_axis, flattening, eccentricity_squared = (
+        _params_from_kwargs(ellps_dict)
+    )
+    sphere = False
+    if ellps_dict["description"] == "Normal Sphere":
+        sphere = True
+    return semi_major_axis, semi_minor_axis, flattening, eccentricity_squared, sphere
+
+
+def _params_from_kwargs(kwargs: dict) -> tuple[float, float, float, float]:
+    """
+    Build Geodesic parameters from input kwargs:
+
+    - a: the semi-major axis (required).
+
+    Need least one of these parameters.
+
+    - b: the semi-minor axis
+    - rf: the reciprocal flattening
+    - f: flattening
+    - es: eccentricity squared
+
+
+    Parameter
+    ---------
+    kwargs: dict
+        The input kwargs for an ellipse.
+
+    Returns
+    -------
+    tuple[float, float, float, float]
+
+    """
+    semi_major_axis = kwargs["a"]
+    if "b" in kwargs:
+        semi_minor_axis = kwargs["b"]
+        eccentricity_squared = 1.0 - semi_minor_axis**2 / semi_major_axis**2
+        flattening = (semi_major_axis - semi_minor_axis) / semi_major_axis
+    elif "rf" in kwargs:
+        flattening = 1.0 / kwargs["rf"]
+        semi_minor_axis = semi_major_axis * (1.0 - flattening)
+        eccentricity_squared = 1.0 - semi_minor_axis**2 / semi_major_axis**2
+    elif "f" in kwargs:
+        flattening = kwargs["f"]
+        semi_minor_axis = semi_major_axis * (1.0 - flattening)
+        eccentricity_squared = 1.0 - (semi_minor_axis / semi_major_axis) ** 2
+    elif "es" in kwargs:
+        eccentricity_squared = kwargs["es"]
+        semi_minor_axis = math.sqrt(
+            semi_major_axis**2 - eccentricity_squared * semi_major_axis**2
+        )
+        flattening = (semi_major_axis - semi_minor_axis) / semi_major_axis
+    elif "e" in kwargs:
+        eccentricity_squared = kwargs["e"] ** 2
+        semi_minor_axis = math.sqrt(
+            semi_major_axis**2 - eccentricity_squared * semi_major_axis**2
+        )
+        flattening = (semi_major_axis - semi_minor_axis) / semi_major_axis
+    else:
+        semi_minor_axis = semi_major_axis
+        flattening = 0.0
+        eccentricity_squared = 0.0
+    return semi_major_axis, semi_minor_axis, flattening, eccentricity_squared
+
+
+
+[docs] +class Geod(_Geod): + """ + performs forward and inverse geodetic, or Great Circle, + computations. The forward computation (using the 'fwd' method) + involves determining latitude, longitude and back azimuth of a + terminus point given the latitude and longitude of an initial + point, plus azimuth and distance. The inverse computation (using + the 'inv' method) involves determining the forward and back + azimuths and distance given the latitudes and longitudes of an + initial and terminus point. + + Attributes + ---------- + initstring: str + The string form of the user input used to create the Geod. + sphere: bool + If True, it is a sphere. + a: float + The ellipsoid equatorial radius, or semi-major axis. + b: float + The ellipsoid polar radius, or semi-minor axis. + es: float + The 'eccentricity' of the ellipse, squared (1-b2/a2). + f: float + The ellipsoid 'flattening' parameter ( (a-b)/a ). + + """ + +
+[docs] + def __init__(self, initstring: str | None = None, **kwargs) -> None: + """ + initialize a Geod class instance. + + Geodetic parameters for specifying the ellipsoid + can be given in a dictionary 'initparams', as keyword arguments, + or as as proj geod initialization string. + + You can get a dictionary of ellipsoids using :func:`pyproj.get_ellps_map` + or with the variable `pyproj.pj_ellps`. + + The parameters of the ellipsoid may also be set directly using + the 'a' (semi-major or equatorial axis radius) keyword, and + any one of the following keywords: 'b' (semi-minor, + or polar axis radius), 'e' (eccentricity), 'es' (eccentricity + squared), 'f' (flattening), or 'rf' (reciprocal flattening). + + See the proj documentation (https://proj.org) for more + information about specifying ellipsoid parameters. + + Example usage: + + >>> from pyproj import Geod + >>> g = Geod(ellps='clrk66') # Use Clarke 1866 ellipsoid. + >>> # specify the lat/lons of some cities. + >>> boston_lat = 42.+(15./60.); boston_lon = -71.-(7./60.) + >>> portland_lat = 45.+(31./60.); portland_lon = -123.-(41./60.) + >>> newyork_lat = 40.+(47./60.); newyork_lon = -73.-(58./60.) + >>> london_lat = 51.+(32./60.); london_lon = -(5./60.) + >>> # compute forward and back azimuths, plus distance + >>> # between Boston and Portland. + >>> az12,az21,dist = g.inv(boston_lon,boston_lat,portland_lon,portland_lat) + >>> f"{az12:.3f} {az21:.3f} {dist:.3f}" + '-66.531 75.654 4164192.708' + >>> # compute latitude, longitude and back azimuth of Portland, + >>> # given Boston lat/lon, forward azimuth and distance to Portland. + >>> endlon, endlat, backaz = g.fwd(boston_lon, boston_lat, az12, dist) + >>> f"{endlat:.3f} {endlon:.3f} {backaz:.3f}" + '45.517 -123.683 75.654' + >>> # compute the azimuths, distances from New York to several + >>> # cities (pass a list) + >>> lons1 = 3*[newyork_lon]; lats1 = 3*[newyork_lat] + >>> lons2 = [boston_lon, portland_lon, london_lon] + >>> lats2 = [boston_lat, portland_lat, london_lat] + >>> az12,az21,dist = g.inv(lons1,lats1,lons2,lats2) + >>> for faz, baz, d in list(zip(az12,az21,dist)): + ... f"{faz:7.3f} {baz:8.3f} {d:12.3f}" + ' 54.663 -123.448 288303.720' + '-65.463 79.342 4013037.318' + ' 51.254 -71.576 5579916.651' + >>> g2 = Geod('+ellps=clrk66') # use proj4 style initialization string + >>> az12,az21,dist = g2.inv(boston_lon,boston_lat,portland_lon,portland_lat) + >>> f"{az12:.3f} {az21:.3f} {dist:.3f}" + '-66.531 75.654 4164192.708' + """ + # if initparams is a proj-type init string, + # convert to dict. + ellpsd: dict[str, str | float] = {} + if initstring is not None: + for kvpair in initstring.split(): + # Actually only +a and +b are needed + # We can ignore safely any parameter that doesn't have a value + if kvpair.find("=") == -1: + continue + key, val = kvpair.split("=") + key = key.lstrip("+") + if key in ["a", "b", "rf", "f", "es", "e"]: + ellpsd[key] = float(val) + else: + ellpsd[key] = val + # merge this dict with kwargs dict. + kwargs = dict(list(kwargs.items()) + list(ellpsd.items())) + sphere = False + if "ellps" in kwargs: + ( + semi_major_axis, + semi_minor_axis, + flattening, + eccentricity_squared, + sphere, + ) = _params_from_ellps_map(kwargs["ellps"]) + else: + ( + semi_major_axis, + semi_minor_axis, + flattening, + eccentricity_squared, + ) = _params_from_kwargs(kwargs) + + if math.fabs(flattening) < 1.0e-8: + sphere = True + + super().__init__( + semi_major_axis, flattening, sphere, semi_minor_axis, eccentricity_squared + )
+ + +
+[docs] + def fwd( # pylint: disable=invalid-name + self, + lons: Any, + lats: Any, + az: Any, + dist: Any, + radians: bool = False, + inplace: bool = False, + return_back_azimuth: bool = True, + ) -> tuple[Any, Any, Any]: + """ + Forward transformation + + Determine longitudes, latitudes and back azimuths of terminus + points given longitudes and latitudes of initial points, + plus forward azimuths and distances. + + .. versionadded:: 3.5.0 inplace + .. versionadded:: 3.5.0 return_back_azimuth + + Accepted numeric scalar or array: + + - :class:`int` + - :class:`float` + - :class:`numpy.floating` + - :class:`numpy.integer` + - :class:`list` + - :class:`tuple` + - :class:`array.array` + - :class:`numpy.ndarray` + - :class:`xarray.DataArray` + - :class:`pandas.Series` + + Parameters + ---------- + lons: scalar or array + Longitude(s) of initial point(s) + lats: scalar or array + Latitude(s) of initial point(s) + az: scalar or array + Forward azimuth(s) + dist: scalar or array + Distance(s) between initial and terminus point(s) + in meters + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + inplace: bool, default=False + If True, will attempt to write the results to the input array + instead of returning a new array. This will fail if the input + is not an array in C order with the double data type. + return_back_azimuth: bool, default=True + If True, the third return value will be the back azimuth, + Otherwise, it will be the forward azimuth. + + Returns + ------- + scalar or array: + Longitude(s) of terminus point(s) + scalar or array: + Latitude(s) of terminus point(s) + scalar or array: + Back azimuth(s) or Forward azimuth(s) + """ + try: + # Fast-path for scalar input, will raise if invalid types are input + # and we can fallback below + return self._fwd_point( + lons, + lats, + az, + dist, + radians=radians, + return_back_azimuth=return_back_azimuth, + ) + except TypeError: + pass + + # process inputs, making copies that support buffer API. + inx, x_data_type = _copytobuffer(lons, inplace=inplace) + iny, y_data_type = _copytobuffer(lats, inplace=inplace) + inz, z_data_type = _copytobuffer(az, inplace=inplace) + ind = _copytobuffer(dist, inplace=inplace)[0] + self._fwd( + inx, iny, inz, ind, radians=radians, return_back_azimuth=return_back_azimuth + ) + # if inputs were lists, tuples or floats, convert back. + outx = _convertback(x_data_type, inx) + outy = _convertback(y_data_type, iny) + outz = _convertback(z_data_type, inz) + return outx, outy, outz
+ + +
+[docs] + def inv( + self, + lons1: Any, + lats1: Any, + lons2: Any, + lats2: Any, + radians: bool = False, + inplace: bool = False, + return_back_azimuth: bool = True, + ) -> tuple[Any, Any, Any]: + """ + + Inverse transformation + + Determine forward and back azimuths, plus distances + between initial points and terminus points. + + .. versionadded:: 3.5.0 inplace + .. versionadded:: 3.5.0 return_back_azimuth + + Accepted numeric scalar or array: + + - :class:`int` + - :class:`float` + - :class:`numpy.floating` + - :class:`numpy.integer` + - :class:`list` + - :class:`tuple` + - :class:`array.array` + - :class:`numpy.ndarray` + - :class:`xarray.DataArray` + - :class:`pandas.Series` + + Parameters + ---------- + lons1: scalar or array + Longitude(s) of initial point(s) + lats1: scalar or array + Latitude(s) of initial point(s) + lons2: scalar or array + Longitude(s) of terminus point(s) + lats2: scalar or array + Latitude(s) of terminus point(s) + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + inplace: bool, default=False + If True, will attempt to write the results to the input array + instead of returning a new array. This will fail if the input + is not an array in C order with the double data type. + return_back_azimuth: bool, default=True + If True, the second return value (azi21) will be the back azimuth + (flipped 180 degrees), Otherwise, it will also be a forward azimuth. + + Returns + ------- + scalar or array: + Forward azimuth(s) (azi12) + scalar or array: + Back azimuth(s) or Forward azimuth(s) (azi21) + scalar or array: + Distance(s) between initial and terminus point(s) + in meters + """ + try: + # Fast-path for scalar input, will raise if invalid types are input + # and we can fallback below + return self._inv_point( + lons1, + lats1, + lons2, + lats2, + radians=radians, + return_back_azimuth=return_back_azimuth, + ) + except TypeError: + pass + + # process inputs, making copies that support buffer API. + inx, x_data_type = _copytobuffer(lons1, inplace=inplace) + iny, y_data_type = _copytobuffer(lats1, inplace=inplace) + inz, z_data_type = _copytobuffer(lons2, inplace=inplace) + ind = _copytobuffer(lats2, inplace=inplace)[0] + self._inv( + inx, iny, inz, ind, radians=radians, return_back_azimuth=return_back_azimuth + ) + # if inputs were lists, tuples or floats, convert back. + outx = _convertback(x_data_type, inx) + outy = _convertback(y_data_type, iny) + outz = _convertback(z_data_type, inz) + return outx, outy, outz
+ + +
+[docs] + def npts( + self, + lon1: float, + lat1: float, + lon2: float, + lat2: float, + npts: int, + radians: bool = False, + initial_idx: int = 1, + terminus_idx: int = 1, + ) -> list: + """ + .. versionadded:: 3.1.0 initial_idx, terminus_idx + + Given a single initial point and terminus point, returns + a list of longitude/latitude pairs describing npts equally + spaced intermediate points along the geodesic between the + initial and terminus points. + + Similar to inv_intermediate(), but with less options. + + Example usage: + + >>> from pyproj import Geod + >>> g = Geod(ellps='clrk66') # Use Clarke 1866 ellipsoid. + >>> # specify the lat/lons of Boston and Portland. + >>> boston_lat = 42.+(15./60.); boston_lon = -71.-(7./60.) + >>> portland_lat = 45.+(31./60.); portland_lon = -123.-(41./60.) + >>> # find ten equally spaced points between Boston and Portland. + >>> lonlats = g.npts(boston_lon,boston_lat,portland_lon,portland_lat,10) + >>> for lon,lat in lonlats: f'{lat:.3f} {lon:.3f}' + '43.528 -75.414' + '44.637 -79.883' + '45.565 -84.512' + '46.299 -89.279' + '46.830 -94.156' + '47.149 -99.112' + '47.251 -104.106' + '47.136 -109.100' + '46.805 -114.051' + '46.262 -118.924' + >>> # test with radians=True (inputs/outputs in radians, not degrees) + >>> import math + >>> dg2rad = math.radians(1.) + >>> rad2dg = math.degrees(1.) + >>> lonlats = g.npts( + ... dg2rad*boston_lon, + ... dg2rad*boston_lat, + ... dg2rad*portland_lon, + ... dg2rad*portland_lat, + ... 10, + ... radians=True + ... ) + >>> for lon,lat in lonlats: f'{rad2dg*lat:.3f} {rad2dg*lon:.3f}' + '43.528 -75.414' + '44.637 -79.883' + '45.565 -84.512' + '46.299 -89.279' + '46.830 -94.156' + '47.149 -99.112' + '47.251 -104.106' + '47.136 -109.100' + '46.805 -114.051' + '46.262 -118.924' + + Parameters + ---------- + lon1: float + Longitude of the initial point + lat1: float + Latitude of the initial point + lon2: float + Longitude of the terminus point + lat2: float + Latitude of the terminus point + npts: int + Number of points to be returned + (including initial and/or terminus points, if required) + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + initial_idx: int, default=1 + if initial_idx==0 then the initial point would be included in the output + (as the first point) + terminus_idx: int, default=1 + if terminus_idx==0 then the terminus point would be included in the output + (as the last point) + Returns + ------- + list of tuples: + list of (lon, lat) points along the geodesic + between the initial and terminus points. + """ + + res = self._inv_or_fwd_intermediate( + lon1=lon1, + lat1=lat1, + lon2_or_azi1=lon2, + lat2=lat2, + npts=npts, + del_s=0, + radians=radians, + initial_idx=initial_idx, + terminus_idx=terminus_idx, + flags=GeodIntermediateFlag.AZIS_DISCARD, + out_lons=None, + out_lats=None, + out_azis=None, + return_back_azimuth=False, + is_fwd=False, + ) + return list(zip(res.lons, res.lats))
+ + +
+[docs] + def inv_intermediate( + self, + lon1: float, + lat1: float, + lon2: float, + lat2: float, + npts: int = 0, + del_s: float = 0, + initial_idx: int = 1, + terminus_idx: int = 1, + radians: bool = False, + flags: GeodIntermediateFlag = GeodIntermediateFlag.DEFAULT, + out_lons: Any | None = None, + out_lats: Any | None = None, + out_azis: Any | None = None, + return_back_azimuth: bool | None = None, + ) -> GeodIntermediateReturn: + """ + .. versionadded:: 3.1.0 + .. versionadded:: 3.5.0 return_back_azimuth + + Given a single initial point and terminus point, + and the number of points, returns + a list of longitude/latitude pairs describing npts equally + spaced intermediate points along the geodesic between the + initial and terminus points. + + npts and del_s parameters are mutually exclusive: + + if npts != 0: + it calculates the distance between the points by + the distance between the initial point and the + terminus point divided by npts + (the number of intermediate points) + else: + it calculates the number of intermediate points by + dividing the distance between the initial and + terminus points by del_s + (delimiter distance between two successive points) + + Similar to npts(), but with more options. + + Example usage: + + >>> from pyproj import Geod + >>> g = Geod(ellps='clrk66') # Use Clarke 1866 ellipsoid. + >>> # specify the lat/lons of Boston and Portland. + >>> boston_lat = 42.+(15./60.); boston_lon = -71.-(7./60.) + >>> portland_lat = 45.+(31./60.); portland_lon = -123.-(41./60.) + >>> # find ten equally spaced points between Boston and Portland. + >>> r = g.inv_intermediate(boston_lon,boston_lat,portland_lon,portland_lat,10) + >>> for lon,lat in zip(r.lons, r.lats): f'{lat:.3f} {lon:.3f}' + '43.528 -75.414' + '44.637 -79.883' + '45.565 -84.512' + '46.299 -89.279' + '46.830 -94.156' + '47.149 -99.112' + '47.251 -104.106' + '47.136 -109.100' + '46.805 -114.051' + '46.262 -118.924' + >>> # test with radians=True (inputs/outputs in radians, not degrees) + >>> import math + >>> dg2rad = math.radians(1.) + >>> rad2dg = math.degrees(1.) + >>> r = g.inv_intermediate( + ... dg2rad*boston_lon, + ... dg2rad*boston_lat, + ... dg2rad*portland_lon, + ... dg2rad*portland_lat, + ... 10, + ... radians=True + ... ) + >>> for lon,lat in zip(r.lons, r.lats): f'{rad2dg*lat:.3f} {rad2dg*lon:.3f}' + '43.528 -75.414' + '44.637 -79.883' + '45.565 -84.512' + '46.299 -89.279' + '46.830 -94.156' + '47.149 -99.112' + '47.251 -104.106' + '47.136 -109.100' + '46.805 -114.051' + '46.262 -118.924' + + Parameters + ---------- + lon1: float + Longitude of the initial point + lat1: float + Latitude of the initial point + lon2: float + Longitude of the terminus point + lat2: float + Latitude of the terminus point + npts: int, default=0 + Number of points to be returned + npts == 0 if del_s != 0 + del_s: float, default=0 + delimiter distance between two successive points + del_s == 0 if npts != 0 + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + initial_idx: int, default=1 + if initial_idx==0 then the initial point would be included in the output + (as the first point) + terminus_idx: int, default=1 + if terminus_idx==0 then the terminus point would be included in the output + (as the last point) + flags: GeodIntermediateFlag, default=GeodIntermediateFlag.DEFAULT + * 1st - round/ceil/trunc (see ``GeodIntermediateFlag.NPTS_*``) + * 2nd - update del_s to the new npts or not + (see ``GeodIntermediateFlag.DEL_S_*``) + * 3rd - if out_azis=None, indicates if to save or discard the azimuths + (see ``GeodIntermediateFlag.AZIS_*``) + * default - round npts, update del_s accordingly, discard azis + out_lons: array, :class:`numpy.ndarray`, optional + Longitude(s) of the intermediate point(s) + If None then buffers would be allocated internnaly + out_lats: array, :class:`numpy.ndarray`, optional + Latitudes(s) of the intermediate point(s) + If None then buffers would be allocated internnaly + out_azis: array, :class:`numpy.ndarray`, optional + az12(s) of the intermediate point(s) + If None then buffers would be allocated internnaly + unless requested otherwise by the flags + return_back_azimuth: bool, default=True + if True, out_azis will store the back azimuth, + Otherwise, out_azis will store the forward azimuth. + + Returns + ------- + GeodIntermediateReturn: + number of points, distance and output arrays (GeodIntermediateReturn docs) + """ + if return_back_azimuth is None: + return_back_azimuth = True + warnings.warn( + "Back azimuth is being returned by default to be compatible with fwd()" + "This is a breaking change for pyproj 3.5+." + "To avoid this warning, set return_back_azimuth=True." + "Otherwise, to restore old behaviour, set return_back_azimuth=False." + "This warning will be removed in future version." + ) + return super()._inv_or_fwd_intermediate( + lon1=lon1, + lat1=lat1, + lon2_or_azi1=lon2, + lat2=lat2, + npts=npts, + del_s=del_s, + radians=radians, + initial_idx=initial_idx, + terminus_idx=terminus_idx, + flags=int(flags), + out_lons=out_lons, + out_lats=out_lats, + out_azis=out_azis, + return_back_azimuth=return_back_azimuth, + is_fwd=False, + )
+ + +
+[docs] + def fwd_intermediate( + self, + lon1: float, + lat1: float, + azi1: float, + npts: int, + del_s: float, + initial_idx: int = 1, + terminus_idx: int = 1, + radians: bool = False, + flags: GeodIntermediateFlag = GeodIntermediateFlag.DEFAULT, + out_lons: Any | None = None, + out_lats: Any | None = None, + out_azis: Any | None = None, + return_back_azimuth: bool | None = None, + ) -> GeodIntermediateReturn: + """ + .. versionadded:: 3.1.0 + .. versionadded:: 3.5.0 return_back_azimuth + + Given a single initial point and azimuth, number of points (npts) + and delimiter distance between two successive points (del_s), returns + a list of longitude/latitude pairs describing npts equally + spaced intermediate points along the geodesic between the + initial and terminus points. + + Example usage: + + >>> from pyproj import Geod + >>> g = Geod(ellps='clrk66') # Use Clarke 1866 ellipsoid. + >>> # specify the lat/lons of Boston and Portland. + >>> boston_lat = 42.+(15./60.); boston_lon = -71.-(7./60.) + >>> portland_lat = 45.+(31./60.); portland_lon = -123.-(41./60.) + >>> az12,az21,dist = g.inv(boston_lon,boston_lat,portland_lon,portland_lat) + >>> # find ten equally spaced points between Boston and Portland. + >>> npts = 10 + >>> del_s = dist/(npts+1) + >>> r = g.fwd_intermediate(boston_lon,boston_lat,az12,npts=npts,del_s=del_s) + >>> for lon,lat in zip(r.lons, r.lats): f'{lat:.3f} {lon:.3f}' + '43.528 -75.414' + '44.637 -79.883' + '45.565 -84.512' + '46.299 -89.279' + '46.830 -94.156' + '47.149 -99.112' + '47.251 -104.106' + '47.136 -109.100' + '46.805 -114.051' + '46.262 -118.924' + >>> # test with radians=True (inputs/outputs in radians, not degrees) + >>> import math + >>> dg2rad = math.radians(1.) + >>> rad2dg = math.degrees(1.) + >>> r = g.fwd_intermediate( + ... dg2rad*boston_lon, + ... dg2rad*boston_lat, + ... dg2rad*az12, + ... npts=npts, + ... del_s=del_s, + ... radians=True + ... ) + >>> for lon,lat in zip(r.lons, r.lats): f'{rad2dg*lat:.3f} {rad2dg*lon:.3f}' + '43.528 -75.414' + '44.637 -79.883' + '45.565 -84.512' + '46.299 -89.279' + '46.830 -94.156' + '47.149 -99.112' + '47.251 -104.106' + '47.136 -109.100' + '46.805 -114.051' + '46.262 -118.924' + + Parameters + ---------- + lon1: float + Longitude of the initial point + lat1: float + Latitude of the initial point + azi1: float + Azimuth from the initial point towards the terminus point + npts: int + Number of points to be returned + (including initial and/or terminus points, if required) + del_s: float + delimiter distance between two successive points + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + initial_idx: int, default=1 + if initial_idx==0 then the initial point would be included in the output + (as the first point) + terminus_idx: int, default=1 + if terminus_idx==0 then the terminus point would be included in the output + (as the last point) + flags: GeodIntermediateFlag, default=GeodIntermediateFlag.DEFAULT + * 1st - round/ceil/trunc (see ``GeodIntermediateFlag.NPTS_*``) + * 2nd - update del_s to the new npts or not + (see ``GeodIntermediateFlag.DEL_S_*``) + * 3rd - if out_azis=None, indicates if to save or discard the azimuths + (see ``GeodIntermediateFlag.AZIS_*``) + * default - round npts, update del_s accordingly, discard azis + out_lons: array, :class:`numpy.ndarray`, optional + Longitude(s) of the intermediate point(s) + If None then buffers would be allocated internnaly + out_lats: array, :class:`numpy.ndarray`, optional + Latitudes(s) of the intermediate point(s) + If None then buffers would be allocated internnaly + out_azis: array, :class:`numpy.ndarray`, optional + az12(s) of the intermediate point(s) + If None then buffers would be allocated internnaly + unless requested otherwise by the flags + return_back_azimuth: bool, default=True + if True, out_azis will store the back azimuth, + Otherwise, out_azis will store the forward azimuth. + + Returns + ------- + GeodIntermediateReturn: + number of points, distance and output arrays (GeodIntermediateReturn docs) + """ + if return_back_azimuth is None: + return_back_azimuth = True + warnings.warn( + "Back azimuth is being returned by default to be compatible with inv()" + "This is a breaking change for pyproj 3.5+." + "To avoid this warning, set return_back_azimuth=True." + "Otherwise, to restore old behaviour, set return_back_azimuth=False." + "This warning will be removed in future version." + ) + return super()._inv_or_fwd_intermediate( + lon1=lon1, + lat1=lat1, + lon2_or_azi1=azi1, + lat2=math.nan, + npts=npts, + del_s=del_s, + radians=radians, + initial_idx=initial_idx, + terminus_idx=terminus_idx, + flags=int(flags), + out_lons=out_lons, + out_lats=out_lats, + out_azis=out_azis, + return_back_azimuth=return_back_azimuth, + is_fwd=True, + )
+ + +
+[docs] + def line_length(self, lons: Any, lats: Any, radians: bool = False) -> float: + """ + .. versionadded:: 2.3.0 + + Calculate the total distance between points along a line (meters). + + >>> from pyproj import Geod + >>> geod = Geod('+a=6378137 +f=0.0033528106647475126') + >>> lats = [-72.9, -71.9, -74.9, -74.3, -77.5, -77.4, -71.7, -65.9, -65.7, + ... -66.6, -66.9, -69.8, -70.0, -71.0, -77.3, -77.9, -74.7] + >>> lons = [-74, -102, -102, -131, -163, 163, 172, 140, 113, + ... 88, 59, 25, -4, -14, -33, -46, -61] + >>> total_length = geod.line_length(lons, lats) + >>> f"{total_length:.3f}" + '14259605.611' + + + Parameters + ---------- + lons: array, :class:`numpy.ndarray`, list, tuple, or scalar + The longitude points along a line. + lats: array, :class:`numpy.ndarray`, list, tuple, or scalar + The latitude points along a line. + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + + Returns + ------- + float: + The total length of the line (meters). + """ + # process inputs, making copies that support buffer API. + inx = _copytobuffer(lons)[0] + iny = _copytobuffer(lats)[0] + return self._line_length(inx, iny, radians=radians)
+ + +
+[docs] + def line_lengths(self, lons: Any, lats: Any, radians: bool = False) -> Any: + """ + .. versionadded:: 2.3.0 + + Calculate the distances between points along a line (meters). + + >>> from pyproj import Geod + >>> geod = Geod(ellps="WGS84") + >>> lats = [-72.9, -71.9, -74.9] + >>> lons = [-74, -102, -102] + >>> for line_length in geod.line_lengths(lons, lats): + ... f"{line_length:.3f}" + '943065.744' + '334805.010' + + Parameters + ---------- + lons: array, :class:`numpy.ndarray`, list, tuple, or scalar + The longitude points along a line. + lats: array, :class:`numpy.ndarray`, list, tuple, or scalar + The latitude points along a line. + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + + Returns + ------- + array, :class:`numpy.ndarray`, list, tuple, or scalar: + The total length of the line (meters). + """ + # process inputs, making copies that support buffer API. + inx, x_data_type = _copytobuffer(lons) + iny = _copytobuffer(lats)[0] + self._line_length(inx, iny, radians=radians) + line_lengths = _convertback(x_data_type, inx) + return line_lengths if x_data_type == DataType.FLOAT else line_lengths[:-1]
+ + +
+[docs] + def polygon_area_perimeter( + self, lons: Any, lats: Any, radians: bool = False + ) -> tuple[float, float]: + """ + .. versionadded:: 2.3.0 + + A simple interface for computing the area (meters^2) and perimeter (meters) + of a geodesic polygon. + + Arbitrarily complex polygons are allowed. In the case self-intersecting + of polygons the area is accumulated "algebraically", e.g., the areas of + the 2 loops in a figure-8 polygon will partially cancel. There's no need + to "close" the polygon by repeating the first vertex. The area returned + is signed with counter-clockwise traversal being treated as positive. + + .. note:: lats should be in the range [-90 deg, 90 deg]. + + + Example usage: + + >>> from pyproj import Geod + >>> geod = Geod('+a=6378137 +f=0.0033528106647475126') + >>> lats = [-72.9, -71.9, -74.9, -74.3, -77.5, -77.4, -71.7, -65.9, -65.7, + ... -66.6, -66.9, -69.8, -70.0, -71.0, -77.3, -77.9, -74.7] + >>> lons = [-74, -102, -102, -131, -163, 163, 172, 140, 113, + ... 88, 59, 25, -4, -14, -33, -46, -61] + >>> poly_area, poly_perimeter = geod.polygon_area_perimeter(lons, lats) + >>> f"{poly_area:.1f} {poly_perimeter:.1f}" + '13376856682207.4 14710425.4' + + + Parameters + ---------- + lons: array, :class:`numpy.ndarray`, list, tuple, or scalar + An array of longitude values. + lats: array, :class:`numpy.ndarray`, list, tuple, or scalar + An array of latitude values. + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + + Returns + ------- + (float, float): + The geodesic area (meters^2) and perimeter (meters) of the polygon. + """ + return self._polygon_area_perimeter( + _copytobuffer(lons)[0], _copytobuffer(lats)[0], radians=radians + )
+ + +
+[docs] + def geometry_length(self, geometry, radians: bool = False) -> float: + """ + .. versionadded:: 2.3.0 + + Returns the geodesic length (meters) of the shapely geometry. + + If it is a Polygon, it will return the sum of the + lengths along the perimeter. + If it is a MultiPolygon or MultiLine, it will return + the sum of the lengths. + + Example usage: + + >>> from pyproj import Geod + >>> from shapely.geometry import Point, LineString + >>> line_string = LineString([Point(1, 2), Point(3, 4)]) + >>> geod = Geod(ellps="WGS84") + >>> f"{geod.geometry_length(line_string):.3f}" + '313588.397' + + Parameters + ---------- + geometry: :class:`shapely.geometry.BaseGeometry` + The geometry to calculate the length from. + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + + Returns + ------- + float: + The total geodesic length of the geometry (meters). + """ + try: + return self.line_length(*geometry.xy, radians=radians) # type: ignore + except (AttributeError, NotImplementedError): + pass + if hasattr(geometry, "exterior"): + return self.geometry_length(geometry.exterior, radians=radians) + if hasattr(geometry, "geoms"): + total_length = 0.0 + for geom in geometry.geoms: + total_length += self.geometry_length(geom, radians=radians) + return total_length + raise GeodError("Invalid geometry provided.")
+ + +
+[docs] + def geometry_area_perimeter( + self, geometry, radians: bool = False + ) -> tuple[float, float]: + """ + .. versionadded:: 2.3.0 + + A simple interface for computing the area (meters^2) and perimeter (meters) + of a geodesic polygon as a shapely geometry. + + Arbitrarily complex polygons are allowed. In the case self-intersecting + of polygons the area is accumulated "algebraically", e.g., the areas of + the 2 loops in a figure-8 polygon will partially cancel. There's no need + to "close" the polygon by repeating the first vertex. + + .. note:: lats should be in the range [-90 deg, 90 deg]. + + .. warning:: The area returned is signed with counter-clockwise (CCW) traversal + being treated as positive. For polygons, holes should use the + opposite traversal to the exterior (if the exterior is CCW, the + holes/interiors should be CW). You can use `shapely.ops.orient` to + modify the orientation. + + If it is a Polygon, it will return the area and exterior perimeter. + It will subtract the area of the interior holes. + If it is a MultiPolygon or MultiLine, it will return + the sum of the areas and perimeters of all geometries. + + + Example usage: + + >>> from pyproj import Geod + >>> from shapely.geometry import LineString, Point, Polygon + >>> geod = Geod(ellps="WGS84") + >>> poly_area, poly_perimeter = geod.geometry_area_perimeter( + ... Polygon( + ... LineString([ + ... Point(1, 1), Point(10, 1), Point(10, 10), Point(1, 10) + ... ]), + ... holes=[LineString([Point(1, 2), Point(3, 4), Point(5, 2)])], + ... ) + ... ) + >>> f"{poly_area:.0f} {poly_perimeter:.0f}" + '944373881400 3979008' + + + Parameters + ---------- + geometry: :class:`shapely.geometry.BaseGeometry` + The geometry to calculate the area and perimeter from. + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + + Returns + ------- + (float, float): + The geodesic area (meters^2) and perimeter (meters) of the polygon. + """ + try: + return self.polygon_area_perimeter( # type: ignore + *geometry.xy, radians=radians + ) + except (AttributeError, NotImplementedError): + pass + # polygon + if hasattr(geometry, "exterior"): + total_area, total_perimeter = self.geometry_area_perimeter( + geometry.exterior, radians=radians + ) + # subtract area of holes + for hole in geometry.interiors: + area, _ = self.geometry_area_perimeter(hole, radians=radians) + total_area += area + return total_area, total_perimeter + # multi geometries + if hasattr(geometry, "geoms"): + total_area = 0.0 + total_perimeter = 0.0 + for geom in geometry.geoms: + area, perimeter = self.geometry_area_perimeter(geom, radians=radians) + total_area += area + total_perimeter += perimeter + return total_area, total_perimeter + raise GeodError("Invalid geometry provided.")
+ + + def __repr__(self) -> str: + # search for ellipse name + for ellps, vals in pj_ellps.items(): + if self.a == vals["a"]: + # self.sphere is True when self.f is zero or very close to + # zero (0), so prevent divide by zero. + if self.b == vals.get("b") or ( + not self.sphere and (1.0 / self.f) == vals.get("rf") + ): + return f"{self.__class__.__name__}(ellps={ellps!r})" + + # no ellipse name found, call super class + return super().__repr__() + + def __eq__(self, other: Any) -> bool: + """ + equality operator == for Geod objects + + Example usage: + + >>> from pyproj import Geod + >>> # Use Clarke 1866 ellipsoid. + >>> gclrk1 = Geod(ellps='clrk66') + >>> # Define Clarke 1866 using parameters + >>> gclrk2 = Geod(a=6378206.4, b=6356583.8) + >>> gclrk1 == gclrk2 + True + >>> # WGS 66 ellipsoid, PROJ style + >>> gwgs66 = Geod('+ellps=WGS66') + >>> # Naval Weapons Lab., 1965 ellipsoid + >>> gnwl9d = Geod('+ellps=NWL9D') + >>> # these ellipsoids are the same + >>> gnwl9d == gwgs66 + True + >>> gclrk1 != gnwl9d # Clarke 1866 is unlike NWL9D + True + """ + if not isinstance(other, _Geod): + return False + + return self.__repr__() == other.__repr__()
+ + + +def reverse_azimuth(azi: Any, radians: bool = False) -> Any: + """ + Reverses the given azimuth (forward <-> backwards) + + .. versionadded:: 3.5.0 + + Accepted numeric scalar or array: + + - :class:`int` + - :class:`float` + - :class:`numpy.floating` + - :class:`numpy.integer` + - :class:`list` + - :class:`tuple` + - :class:`array.array` + - :class:`numpy.ndarray` + - :class:`xarray.DataArray` + - :class:`pandas.Series` + + Parameters + ---------- + azi: scalar or array + The azimuth. + radians: bool, default=False + If True, the input data is assumed to be in radians. + Otherwise, the data is assumed to be in degrees. + + Returns + ------- + scalar or array: + The reversed azimuth (forward <-> backwards) + """ + inazi, azi_data_type = _copytobuffer(azi) + _reverse_azimuth(inazi, radians=radians) + return _convertback(azi_data_type, inazi) +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/network.html b/3.7.0/_modules/pyproj/network.html new file mode 100644 index 000000000..3b5107301 --- /dev/null +++ b/3.7.0/_modules/pyproj/network.html @@ -0,0 +1,375 @@ + + + + + + + + pyproj.network - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.network

+"""
+Module for managing the PROJ network settings.
+"""
+
+import os
+from pathlib import Path
+
+import certifi
+
+from pyproj._context import _set_context_ca_bundle_path
+from pyproj._network import (  # noqa: F401 pylint: disable=unused-import
+    is_network_enabled,
+    set_network_enabled,
+)
+
+
+
+[docs] +def set_ca_bundle_path(ca_bundle_path: Path | str | bool | None = None) -> None: + """ + .. versionadded:: 3.0.0 + + Sets the path to the CA Bundle used by the `curl` + built into PROJ when PROJ network is enabled. + + See: :c:func:`proj_context_set_ca_bundle_path` + + Environment variables: + + - PROJ_CURL_CA_BUNDLE + - CURL_CA_BUNDLE + - SSL_CERT_FILE + + Parameters + ---------- + ca_bundle_path: Path | str | bool | None, optional + Default is None, which only uses the `certifi` package path as a fallback if + the environment variables are not set. If a path is passed in, then + that will be the path used. If it is set to True, then it will default + to using the path provided, by the `certifi` package. If it is set to False + or an empty string then it will default to the system settings or environment + variables. + """ + env_var_names = ("PROJ_CURL_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_CERT_FILE") + if ca_bundle_path is False: + # need to reset CA Bundle path to use system settings + # or environment variables because it + # could have been changed by the user previously + ca_bundle_path = "" + elif isinstance(ca_bundle_path, (str, Path)): + ca_bundle_path = str(ca_bundle_path) + elif (ca_bundle_path is True) or not any( + env_var_name in os.environ for env_var_name in env_var_names + ): + ca_bundle_path = certifi.where() + else: + # reset CA Bundle path to use system settings + # or environment variables + ca_bundle_path = "" + + _set_context_ca_bundle_path(ca_bundle_path)
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/proj.html b/3.7.0/_modules/pyproj/proj.html new file mode 100644 index 000000000..3a938e539 --- /dev/null +++ b/3.7.0/_modules/pyproj/proj.html @@ -0,0 +1,634 @@ + + + + + + + + pyproj.proj - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.proj

+"""
+Performs cartographic transformations (converts from
+longitude,latitude to native map projection x,y coordinates and
+vice versa) using PROJ (https://proj.org).
+
+A Proj class instance is initialized with proj map projection
+control parameter key/value pairs. The key/value pairs can
+either be passed in a dictionary, or as keyword arguments,
+or as a PROJ string (compatible with the proj command). See
+:ref:`projections` for examples of
+key/value pairs defining different map projections.
+
+Calling a Proj class instance with the arguments lon, lat will
+convert lon/lat (in degrees) to x/y native map projection
+coordinates (in meters).
+"""
+
+import re
+import warnings
+from typing import Any
+
+from pyproj._compat import cstrencode
+from pyproj._transformer import Factors
+from pyproj.crs import CRS
+from pyproj.enums import TransformDirection
+from pyproj.list import get_proj_operations_map
+from pyproj.transformer import Transformer, TransformerFromPipeline
+from pyproj.utils import _convertback, _copytobuffer
+
+pj_list = get_proj_operations_map()
+
+
+
+[docs] +class Proj(Transformer): + """ + Performs cartographic transformations. Converts from + longitude, latitude to native map projection x,y coordinates and + vice versa using PROJ (https://proj.org). + + Attributes + ---------- + srs: str + The string form of the user input used to create the Proj. + crs: pyproj.crs.CRS + The CRS object associated with the Proj. + + """ + +
+[docs] + def __init__( + self, projparams: Any | None = None, preserve_units: bool = True, **kwargs + ) -> None: + """ + A Proj class instance is initialized with proj map projection + control parameter key/value pairs. The key/value pairs can + either be passed in a dictionary, or as keyword arguments, + or as a PROJ string (compatible with the proj command). See + :ref:`projections` for examples of + key/value pairs defining different map projections. + + Parameters + ---------- + projparams: int, str, dict, pyproj.CRS + A PROJ or WKT string, PROJ dict, EPSG integer, or a pyproj.CRS instance. + preserve_units: bool + If false, will ensure +units=m. + **kwargs: + PROJ projection parameters. + + + Example usage: + + >>> from pyproj import Proj + >>> p = Proj(proj='utm',zone=10,ellps='WGS84', preserve_units=False) + >>> x,y = p(-120.108, 34.36116666) + >>> 'x=%9.3f y=%11.3f' % (x,y) + 'x=765975.641 y=3805993.134' + >>> 'lon=%8.3f lat=%5.3f' % p(x,y,inverse=True) + 'lon=-120.108 lat=34.361' + >>> # do 3 cities at a time in a tuple (Fresno, LA, SF) + >>> lons = (-119.72,-118.40,-122.38) + >>> lats = (36.77, 33.93, 37.62 ) + >>> x,y = p(lons, lats) + >>> 'x: %9.3f %9.3f %9.3f' % x + 'x: 792763.863 925321.537 554714.301' + >>> 'y: %9.3f %9.3f %9.3f' % y + 'y: 4074377.617 3763936.941 4163835.303' + >>> lons, lats = p(x, y, inverse=True) # inverse transform + >>> 'lons: %8.3f %8.3f %8.3f' % lons + 'lons: -119.720 -118.400 -122.380' + >>> 'lats: %8.3f %8.3f %8.3f' % lats + 'lats: 36.770 33.930 37.620' + >>> p2 = Proj('+proj=utm +zone=10 +ellps=WGS84', preserve_units=False) + >>> x,y = p2(-120.108, 34.36116666) + >>> 'x=%9.3f y=%11.3f' % (x,y) + 'x=765975.641 y=3805993.134' + >>> p = Proj("EPSG:32667", preserve_units=False) + >>> 'x=%12.3f y=%12.3f (meters)' % p(-114.057222, 51.045) + 'x=-1783506.250 y= 6193827.033 (meters)' + >>> p = Proj("EPSG:32667") + >>> 'x=%12.3f y=%12.3f (feet)' % p(-114.057222, 51.045) + 'x=-5851386.754 y=20320914.191 (feet)' + >>> # test data with radian inputs + >>> p1 = Proj("EPSG:4214") + >>> x1, y1 = p1(116.366, 39.867) + >>> f'{x1:.3f} {y1:.3f}' + '116.366 39.867' + >>> x2, y2 = p1(x1, y1, inverse=True) + >>> f'{x2:.3f} {y2:.3f}' + '116.366 39.867' + """ + self.crs = CRS.from_user_input(projparams, **kwargs) + # make sure units are meters if preserve_units is False. + if not preserve_units and "foot" in self.crs.axis_info[0].unit_name: + # ignore export to PROJ string deprecation warning + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + "You will likely lose important projection information", + UserWarning, + ) + projstring = self.crs.to_proj4(4) + projstring = re.sub(r"\s\+units=[\w-]+", "", projstring) + projstring += " +units=m" + self.crs = CRS(projstring) + + # ignore export to PROJ string deprecation warning + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + "You will likely lose important projection information", + UserWarning, + ) + projstring = self.crs.to_proj4() or self.crs.srs + + self.srs = re.sub(r"\s\+?type=crs", "", projstring).strip() + super().__init__(TransformerFromPipeline(cstrencode(self.srs)))
+ + +
+[docs] + def __call__( + self, + longitude: Any, + latitude: Any, + inverse: bool = False, + errcheck: bool = False, + radians: bool = False, + ) -> tuple[Any, Any]: + """ + Calling a Proj class instance with the arguments lon, lat will + convert lon/lat (in degrees) to x/y native map projection + coordinates (in meters). + + Inputs should be doubles (they will be cast to doubles if they + are not, causing a slight performance hit). + + Works with numpy and regular python array objects, python + sequences and scalars, but is fastest for array objects. + + Accepted numeric scalar or array: + + - :class:`int` + - :class:`float` + - :class:`numpy.floating` + - :class:`numpy.integer` + - :class:`list` + - :class:`tuple` + - :class:`array.array` + - :class:`numpy.ndarray` + - :class:`xarray.DataArray` + - :class:`pandas.Series` + + Parameters + ---------- + longitude: scalar or array + Input longitude coordinate(s). + latitude: scalar or array + Input latitude coordinate(s). + inverse: bool, default=False + If inverse is True the inverse transformation from x/y to + lon/lat is performed. + radians: bool, default=False + If True, will expect input data to be in radians and will return radians + if the projection is geographic. Otherwise, it uses degrees. + This does not work with pyproj 2 and is ignored. It will be enabled again + in pyproj 3. + errcheck: bool, default=False + If True, an exception is raised if the errors are found in the process. + If False, ``inf`` is returned for errors. + + Returns + ------- + tuple[Any, Any]: + The transformed coordinates. + """ + if inverse: + direction = TransformDirection.INVERSE + else: + direction = TransformDirection.FORWARD + return self.transform( + xx=longitude, + yy=latitude, + direction=direction, + errcheck=errcheck, + radians=radians, + )
+ + +
+[docs] + def get_factors( + self, + longitude: Any, + latitude: Any, + radians: bool = False, + errcheck: bool = False, + ) -> Factors: + """ + .. versionadded:: 2.6.0 + + Calculate various cartographic properties, such as scale factors, angular + distortion and meridian convergence. Depending on the underlying projection + values will be calculated either numerically (default) or analytically. + + The function also calculates the partial derivatives of the given + coordinate. + + Accepted numeric scalar or array: + + - :class:`int` + - :class:`float` + - :class:`numpy.floating` + - :class:`numpy.integer` + - :class:`list` + - :class:`tuple` + - :class:`array.array` + - :class:`numpy.ndarray` + - :class:`xarray.DataArray` + - :class:`pandas.Series` + + Parameters + ---------- + longitude: scalar or array + Input longitude coordinate(s). + latitude: scalar or array + Input latitude coordinate(s). + radians: bool, default=False + If True, will expect input data to be in radians and will return radians + if the projection is geographic. Otherwise, it uses degrees. + errcheck: bool, default=False + If True, an exception is raised if the errors are found in the process. + If False, ``inf`` is returned on error. + + Returns + ------- + Factors + """ + # process inputs, making copies that support buffer API. + inx, x_data_type = _copytobuffer(longitude) + iny = _copytobuffer(latitude)[0] + + # calculate the factors + factors = self._transformer._get_factors( + inx, iny, radians=radians, errcheck=errcheck + ) + + # if inputs were lists, tuples or floats, convert back. + return Factors( + meridional_scale=_convertback(x_data_type, factors.meridional_scale), + parallel_scale=_convertback(x_data_type, factors.parallel_scale), + areal_scale=_convertback(x_data_type, factors.areal_scale), + angular_distortion=_convertback(x_data_type, factors.angular_distortion), + meridian_parallel_angle=_convertback( + x_data_type, factors.meridian_parallel_angle + ), + meridian_convergence=_convertback( + x_data_type, factors.meridian_convergence + ), + tissot_semimajor=_convertback(x_data_type, factors.tissot_semimajor), + tissot_semiminor=_convertback(x_data_type, factors.tissot_semiminor), + dx_dlam=_convertback(x_data_type, factors.dx_dlam), + dx_dphi=_convertback(x_data_type, factors.dx_dphi), + dy_dlam=_convertback(x_data_type, factors.dy_dlam), + dy_dphi=_convertback(x_data_type, factors.dy_dphi), + )
+ + +
+[docs] + def definition_string(self) -> str: + """Returns formal definition string for projection + + >>> Proj("EPSG:4326").definition_string() + 'proj=longlat datum=WGS84 no_defs ellps=WGS84 towgs84=0,0,0' + """ + return self.definition
+ + +
+[docs] + def to_latlong_def(self) -> str | None: + """return the definition string of the geographic (lat/lon) + coordinate version of the current projection""" + return self.crs.geodetic_crs.to_proj4(4) if self.crs.geodetic_crs else None
+ + +
+[docs] + def to_latlong(self) -> "Proj": + """return a new Proj instance which is the geographic (lat/lon) + coordinate version of the current projection""" + return Proj(self.crs.geodetic_crs)
+ + + def __reduce__(self) -> tuple[type["Proj"], tuple[str]]: + """special method that allows pyproj.Proj instance to be pickled""" + return self.__class__, (self.crs.srs,)
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/sync.html b/3.7.0/_modules/pyproj/sync.html new file mode 100644 index 000000000..e27502b34 --- /dev/null +++ b/3.7.0/_modules/pyproj/sync.html @@ -0,0 +1,595 @@ + + + + + + + + pyproj.sync - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.sync

+"""
+Based on the logic in the PROJ projsync CLI program
+
+https://github.com/OSGeo/PROJ/blob/9ff543c4ffd86152bc58d0a0164b2ce9ebbb8bec/src/apps/projsync.cpp
+"""
+
+import hashlib
+import json
+import os
+from datetime import datetime
+from functools import partial
+from pathlib import Path
+from typing import Any
+from urllib.request import urlretrieve
+
+from pyproj._sync import get_proj_endpoint
+from pyproj.aoi import BBox
+from pyproj.datadir import get_data_dir, get_user_data_dir
+
+
+def _bbox_from_coords(coords: list) -> BBox | None:
+    """
+    Get the bounding box from coordinates
+    """
+    try:
+        xxx, yyy = zip(*coords)
+        return BBox(west=min(xxx), south=min(yyy), east=max(xxx), north=max(yyy))
+    except ValueError:
+        pass
+    coord_bbox = None
+    for coord_set in coords:
+        bbox = _bbox_from_coords(coord_set)
+        if coord_bbox is None:
+            coord_bbox = bbox
+        else:
+            coord_bbox.west = min(coord_bbox.west, bbox.west)
+            coord_bbox.south = min(coord_bbox.south, bbox.south)
+            coord_bbox.north = max(coord_bbox.north, bbox.north)
+            coord_bbox.east = max(coord_bbox.east, bbox.east)
+    return coord_bbox
+
+
+def _bbox_from_geom(geom: dict[str, Any]) -> BBox | None:
+    """
+    Get the bounding box from geojson geometry
+    """
+    if "coordinates" not in geom or "type" not in geom:
+        return None
+    coordinates = geom["coordinates"]
+    if geom["type"] != "MultiPolygon":
+        return _bbox_from_coords(coordinates)
+    found_minus_180 = False
+    found_plus_180 = False
+    bboxes = []
+    for coordinate_set in coordinates:
+        bbox = _bbox_from_coords(coordinate_set)
+        if bbox is None:
+            continue
+        if bbox.west == -180:
+            found_minus_180 = True
+        elif bbox.east == 180:
+            found_plus_180 = True
+        bboxes.append(bbox)
+    grid_bbox = None
+    for bbox in bboxes:
+        if found_minus_180 and found_plus_180 and bbox.west == -180:
+            bbox.west = 180
+            bbox.east += 360
+        if grid_bbox is None:
+            grid_bbox = bbox
+        else:
+            grid_bbox.west = min(grid_bbox.west, bbox.west)
+            grid_bbox.south = min(grid_bbox.south, bbox.south)
+            grid_bbox.north = max(grid_bbox.north, bbox.north)
+            grid_bbox.east = max(grid_bbox.east, bbox.east)
+    return grid_bbox
+
+
+def _filter_bbox(
+    feature: dict[str, Any], bbox: BBox, spatial_test: str, include_world_coverage: bool
+) -> bool:
+    """
+    Filter by the bounding box. Designed to use with 'filter'
+    """
+    geom = feature.get("geometry")
+    if geom is not None:
+        geom_bbox = _bbox_from_geom(geom)
+        if geom_bbox is None:
+            return False
+        if (
+            geom_bbox.east - geom_bbox.west > 359
+            and geom_bbox.north - geom_bbox.south > 179
+        ):
+            if not include_world_coverage:
+                return False
+            geom_bbox.west = -float("inf")
+            geom_bbox.east = float("inf")
+        elif geom_bbox.east > 180 and bbox.west < -180:
+            geom_bbox.west -= 360
+            geom_bbox.east -= 360
+        return getattr(bbox, spatial_test)(geom_bbox)
+    return False
+
+
+def _filter_properties(
+    feature: dict[str, Any],
+    source_id: str | None = None,
+    area_of_use: str | None = None,
+    filename: str | None = None,
+) -> bool:
+    """
+    Filter by the properties. Designed to use with 'filter'
+    """
+    properties = feature.get("properties")
+    if not properties:
+        return False
+    p_filename = properties.get("name")
+    p_source_id = properties.get("source_id")
+    if not p_filename or not p_source_id:
+        return False
+    source_id__matched = source_id is None or source_id in p_source_id
+    area_of_use__matched = area_of_use is None or area_of_use in properties.get(
+        "area_of_use", ""
+    )
+    filename__matched = filename is None or filename in p_filename
+    if source_id__matched and area_of_use__matched and filename__matched:
+        return True
+    return False
+
+
+def _is_download_needed(grid_name: str) -> bool:
+    """
+    Run through all of the PROJ directories to see if the
+    file already exists.
+    """
+    if Path(get_user_data_dir(), grid_name).exists():
+        return False
+    for data_dir in get_data_dir().split(os.pathsep):
+        if Path(data_dir, grid_name).exists():
+            return False
+    return True
+
+
+def _filter_download_needed(feature: dict[str, Any]) -> bool:
+    """
+    Filter grids so only those that need to be downloaded are included.
+    """
+    properties = feature.get("properties")
+    if not properties:
+        return False
+    filename = properties.get("name")
+    if not filename:
+        return False
+    return _is_download_needed(filename)
+
+
+def _sha256sum(input_file):
+    """
+    Return sha256 checksum of file given by path.
+    """
+
+    hasher = hashlib.sha256()
+    with open(input_file, "rb") as file:
+        for chunk in iter(lambda: file.read(65536), b""):
+            hasher.update(chunk)
+
+    return hasher.hexdigest()
+
+
+def _download_resource_file(
+    file_url, short_name, directory, verbose=False, sha256=None
+):
+    """
+    Download resource file from PROJ url
+    """
+    if verbose:
+        print(f"Downloading: {file_url}")
+    tmp_path = Path(directory, f"{short_name}.part")
+    try:
+        urlretrieve(file_url, tmp_path)
+        if sha256 is not None and sha256 != _sha256sum(tmp_path):
+            raise RuntimeError(f"SHA256 mismatch: {short_name}")
+        tmp_path.replace(Path(directory, short_name))
+    finally:
+        try:
+            os.remove(tmp_path)
+        except FileNotFoundError:
+            pass
+
+
+def _load_grid_geojson(target_directory: str | Path | None = None) -> dict[str, Any]:
+    """
+    Returns
+    -------
+    dict[str, Any]:
+        The PROJ grid data list.
+    """
+    if target_directory is None:
+        target_directory = get_user_data_dir(True)
+    local_path = Path(target_directory, "files.geojson")
+    if not local_path.exists() or (
+        (datetime.utcnow() - datetime.fromtimestamp(local_path.stat().st_mtime)).days
+        > 0
+    ):
+        _download_resource_file(
+            file_url=f"{get_proj_endpoint()}/files.geojson",
+            short_name="files.geojson",
+            directory=target_directory,
+        )
+    return json.loads(local_path.read_text(encoding="utf-8"))
+
+
+
+[docs] +def get_transform_grid_list( + source_id: str | None = None, + area_of_use: str | None = None, + filename: str | None = None, + bbox: BBox | None = None, + spatial_test: str = "intersects", + include_world_coverage: bool = True, + include_already_downloaded: bool = False, + target_directory: str | Path | None = None, +) -> tuple: + """ + Get a list of transform grids that can be downloaded. + + Parameters + ---------- + source_id: str, optional + area_of_use: str, optional + filename: str, optional + bbox: BBox, optional + spatial_test: str, default="intersects" + Can be "contains" or "intersects". + include_world_coverage: bool, default=True + If True, it will include grids with a global extent. + include_already_downloaded: bool, default=False + If True, it will list grids regardless of if they are downloaded. + target_directory: str | Path, optional + The directory to download the geojson file to. + Default is the user writable directory. + + Returns + ------- + list[dict[str, Any]]: + A list of geojson data of containing information about features + that can be downloaded. + """ + features = _load_grid_geojson(target_directory=target_directory)["features"] + if bbox is not None: + if bbox.west > 180 and bbox.east > bbox.west: + bbox.west -= 360 + bbox.east -= 360 + elif bbox.west < -180 and bbox.east > bbox.west: + bbox.west += 360 + bbox.east += 360 + elif abs(bbox.west) < 180 and abs(bbox.east) < 180 and bbox.east < bbox.west: + bbox.east += 360 + features = filter( + partial( + _filter_bbox, + bbox=bbox, + spatial_test=spatial_test, + include_world_coverage=include_world_coverage, + ), + features, + ) + # filter by properties + features = filter( + partial( + _filter_properties, + source_id=source_id, + area_of_use=area_of_use, + filename=filename, + ), + features, + ) + if include_already_downloaded: + return tuple(features) + return tuple(filter(_filter_download_needed, features))
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_modules/pyproj/transformer.html b/3.7.0/_modules/pyproj/transformer.html new file mode 100644 index 000000000..5a61069f8 --- /dev/null +++ b/3.7.0/_modules/pyproj/transformer.html @@ -0,0 +1,1703 @@ + + + + + + + + pyproj.transformer - pyproj 3.7.0 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark, in light mode + + + + + + + + + + + + + + + Auto light/dark, in dark mode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Skip to content + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for pyproj.transformer

+"""
+The transformer module is for performing cartographic transformations.
+"""
+
+__all__ = [
+    "transform",
+    "itransform",
+    "Transformer",
+    "TransformerGroup",
+    "AreaOfInterest",
+]
+import threading
+import warnings
+from abc import ABC, abstractmethod
+from array import array
+from collections.abc import Iterable, Iterator
+from dataclasses import dataclass
+from itertools import chain, islice
+from pathlib import Path
+from typing import Any, overload
+
+from pyproj import CRS
+from pyproj._compat import cstrencode
+from pyproj._context import _clear_proj_error
+from pyproj._crs import AreaOfUse, CoordinateOperation
+from pyproj._transformer import (  # noqa: F401 pylint: disable=unused-import
+    AreaOfInterest,
+    _Transformer,
+    _TransformerGroup,
+)
+from pyproj.datadir import get_user_data_dir
+from pyproj.enums import ProjVersion, TransformDirection, WktVersion
+from pyproj.exceptions import ProjError
+from pyproj.sync import _download_resource_file
+from pyproj.utils import _convertback, _copytobuffer
+
+
+class TransformerMaker(ABC):
+    """
+    .. versionadded:: 3.1.0
+
+    Base class for generating new instances
+    of the Cython _Transformer class for
+    thread safety in the Transformer class.
+    """
+
+    @abstractmethod
+    def __call__(self) -> _Transformer:
+        """
+        Returns
+        -------
+        _Transformer
+        """
+        raise NotImplementedError
+
+
+@dataclass(frozen=True)
+class TransformerUnsafe(TransformerMaker):
+    """
+    .. versionadded:: 3.1.0
+
+    Returns the original Cython _Transformer
+    and is not thread-safe.
+    """
+
+    transformer: _Transformer
+
+    def __call__(self) -> _Transformer:
+        """
+        Returns
+        -------
+        _Transformer
+        """
+        return self.transformer
+
+
+@dataclass(frozen=True)
+class TransformerFromCRS(  # pylint: disable=too-many-instance-attributes
+    TransformerMaker
+):
+    """
+    .. versionadded:: 3.1.0
+
+    .. versionadded:: 3.4.0 force_over
+
+    Generates a Cython _Transformer class from input CRS data.
+    """
+
+    crs_from: bytes
+    crs_to: bytes
+    always_xy: bool
+    area_of_interest: AreaOfInterest | None
+    authority: str | None
+    accuracy: str | None
+    allow_ballpark: bool | None
+    force_over: bool = False
+    only_best: bool | None = None
+
+    def __call__(self) -> _Transformer:
+        """
+        Returns
+        -------
+        _Transformer
+        """
+        return _Transformer.from_crs(
+            self.crs_from,
+            self.crs_to,
+            always_xy=self.always_xy,
+            area_of_interest=self.area_of_interest,
+            authority=self.authority,
+            accuracy=self.accuracy,
+            allow_ballpark=self.allow_ballpark,
+            force_over=self.force_over,
+            only_best=self.only_best,
+        )
+
+
+@dataclass(frozen=True)
+class TransformerFromPipeline(TransformerMaker):
+    """
+    .. versionadded:: 3.1.0
+
+    Generates a Cython _Transformer class from input pipeline data.
+    """
+
+    proj_pipeline: bytes
+
+    def __call__(self) -> _Transformer:
+        """
+        Returns
+        -------
+        _Transformer
+        """
+        return _Transformer.from_pipeline(self.proj_pipeline)
+
+
+
+[docs] +class TransformerGroup(_TransformerGroup): + """ + The TransformerGroup is a set of possible transformers from one CRS to another. + + .. versionadded:: 2.3.0 + + .. warning:: CoordinateOperation and Transformer objects + returned are not thread-safe. + + From PROJ docs:: + + The operations are sorted with the most relevant ones first: by + descending area (intersection of the transformation area with the + area of interest, or intersection of the transformation with the + area of use of the CRS), and by increasing accuracy. Operations + with unknown accuracy are sorted last, whatever their area. + + """ + +
+[docs] + def __init__( + self, + crs_from: Any, + crs_to: Any, + always_xy: bool = False, + area_of_interest: AreaOfInterest | None = None, + authority: str | None = None, + accuracy: float | None = None, + allow_ballpark: bool = True, + allow_superseded: bool = False, + ) -> None: + """Get all possible transformations from a :obj:`pyproj.crs.CRS` + or input used to create one. + + .. versionadded:: 3.4.0 authority, accuracy, allow_ballpark + .. versionadded:: 3.6.0 allow_superseded + + Parameters + ---------- + crs_from: pyproj.crs.CRS or input used to create one + Projection of input data. + crs_to: pyproj.crs.CRS or input used to create one + Projection of output data. + always_xy: bool, default=False + If true, the transform method will accept as input and return as output + coordinates using the traditional GIS order, that is longitude, latitude + for geographic CRS and easting, northing for most projected CRS. + area_of_interest: :class:`.AreaOfInterest`, optional + The area of interest to help order the transformations based on the + best operation for the area. + authority: str, optional + When not specified, coordinate operations from any authority will be + searched, with the restrictions set in the + authority_to_authority_preference database table related to the + authority of the source/target CRS themselves. If authority is set + to “any”, then coordinate operations from any authority will be + searched. If authority is a non-empty string different from "any", + then coordinate operations will be searched only in that authority + namespace (e.g. EPSG). + accuracy: float, optional + The minimum desired accuracy (in metres) of the candidate + coordinate operations. + allow_ballpark: bool, default=True + Set to False to disallow the use of Ballpark transformation + in the candidate coordinate operations. Default is to allow. + allow_superseded: bool, default=False + Set to True to allow the use of superseded (but not deprecated) + transformations in the candidate coordinate operations. Default is + to disallow. + + """ + super().__init__( + CRS.from_user_input(crs_from)._crs, + CRS.from_user_input(crs_to)._crs, + always_xy=always_xy, + area_of_interest=area_of_interest, + authority=authority, + accuracy=-1 if accuracy is None else accuracy, + allow_ballpark=allow_ballpark, + allow_superseded=allow_superseded, + ) + for iii, transformer in enumerate(self._transformers): + # pylint: disable=unsupported-assignment-operation + self._transformers[iii] = Transformer(TransformerUnsafe(transformer))
+ + + @property + def transformers(self) -> list["Transformer"]: + """ + list[:obj:`Transformer`]: + List of available :obj:`Transformer` + associated with the transformation. + """ + return self._transformers + + @property + def unavailable_operations(self) -> list[CoordinateOperation]: + """ + list[:obj:`pyproj.crs.CoordinateOperation`]: + List of :obj:`pyproj.crs.CoordinateOperation` that are not + available due to missing grids. + """ + return self._unavailable_operations + + @property + def best_available(self) -> bool: + """ + bool: If True, the best possible transformer is available. + """ + return self._best_available + +
+[docs] + def download_grids( + self, + directory: str | Path | None = None, + open_license: bool = True, + verbose: bool = False, + ) -> None: + """ + .. versionadded:: 3.0.0 + + Download missing grids that can be downloaded automatically. + + .. warning:: There are cases where the URL to download the grid is missing. + In those cases, you can enable enable + :ref:`debugging-internal-proj` and perform a + transformation. The logs will show the grids PROJ searches for. + + Parameters + ---------- + directory: str or Path, optional + The directory to download the grids to. + Defaults to :func:`pyproj.datadir.get_user_data_dir` + open_license: bool, default=True + If True, will only download grids with an open license. + verbose: bool, default=False + If True, will print information about grids downloaded. + """ + if directory is None: + directory = get_user_data_dir(True) + # pylint: disable=not-an-iterable + for unavailable_operation in self.unavailable_operations: + for grid in unavailable_operation.grids: + if ( + not grid.available + and grid.url.endswith(grid.short_name) + and grid.direct_download + and (grid.open_license or not open_license) + ): + _download_resource_file( + file_url=grid.url, + short_name=grid.short_name, + directory=directory, + verbose=verbose, + ) + elif not grid.available and verbose: + warnings.warn(f"Skipped: {grid}")
+ + + def __repr__(self) -> str: + return ( + f"<TransformerGroup: best_available={self.best_available}>\n" + f"- transformers: {len(self.transformers)}\n" + f"- unavailable_operations: {len(self.unavailable_operations)}" + )
+ + + +class TransformerLocal(threading.local): + """ + Threading local instance for cython _Transformer class. + + For more details, see: + https://github.com/pyproj4/pyproj/issues/782 + """ + + def __init__(self): + self.transformer = None # Initialises in each thread + super().__init__() + + +
+[docs] +class Transformer: + """ + The Transformer class is for facilitating re-using + transforms without needing to re-create them. The goal + is to make repeated transforms faster. + + Additionally, it provides multiple methods for initialization. + + .. versionadded:: 2.1.0 + + """ + + def __init__( + self, + transformer_maker: TransformerMaker | None = None, + ) -> None: + if not isinstance(transformer_maker, TransformerMaker): + _clear_proj_error() + raise ProjError( + "Transformer must be initialized using: " + "'from_crs' or 'from_pipeline'." + ) + + self._local = TransformerLocal() + self._local.transformer = transformer_maker() + self._transformer_maker = transformer_maker + + def __getstate__(self) -> dict[str, Any]: + return {"_transformer_maker": self._transformer_maker} + + def __setstate__(self, state: dict[str, Any]): + self.__dict__.update(state) + self._local = TransformerLocal() + self._local.transformer = self._transformer_maker() + + @property + def _transformer(self): + """ + The Cython _Transformer object for this thread. + + Returns + ------- + _Transformer + """ + if self._local.transformer is None: + self._local.transformer = self._transformer_maker() + return self._local.transformer + + @property + def name(self) -> str: + """ + str: Name of the projection. + """ + return self._transformer.id + + @property + def description(self) -> str: + """ + str: Description of the projection. + """ + return self._transformer.description + + @property + def definition(self) -> str: + """ + str: Definition of the projection. + """ + return self._transformer.definition + + @property + def has_inverse(self) -> bool: + """ + bool: True if an inverse mapping exists. + """ + return self._transformer.has_inverse + + @property + def accuracy(self) -> float: + """ + float: Expected accuracy of the transformation. -1 if unknown. + """ + return self._transformer.accuracy + + @property + def area_of_use(self) -> AreaOfUse: + """ + .. versionadded:: 2.3.0 + + Returns + ------- + AreaOfUse: + The area of use object with associated attributes. + """ + return self._transformer.area_of_use + + @property + def remarks(self) -> str: + """ + .. versionadded:: 2.4.0 + + Returns + ------- + str: + Remarks about object. + """ + return self._transformer.remarks + + @property + def scope(self) -> str: + """ + .. versionadded:: 2.4.0 + + Returns + ------- + str: + Scope of object. + """ + return self._transformer.scope + + @property + def operations(self) -> tuple[CoordinateOperation] | None: + """ + .. versionadded:: 2.4.0 + + Returns + ------- + tuple[CoordinateOperation]: + The operations in a concatenated operation. + """ + return self._transformer.operations + +
+[docs] + def get_last_used_operation(self) -> "Transformer": + """ + .. versionadded:: 3.4.0 + + .. note:: Requires PROJ 9.1+ + + See: :c:func:`proj_trans_get_last_used_operation` + + Returns + ------- + Transformer: + The operation used in the transform call. + """ + return Transformer( + TransformerUnsafe(self._transformer.get_last_used_operation()) + )
+ + + @property + def is_network_enabled(self) -> bool: + """ + .. versionadded:: 3.0.0 + + Returns + ------- + bool: + If the network is enabled. + """ + return self._transformer.is_network_enabled + + @property + def source_crs(self) -> CRS | None: + """ + .. versionadded:: 3.3.0 + + Returns + ------- + CRS | None: + The source CRS of a CoordinateOperation. + """ + return ( + None + if self._transformer.source_crs is None + else CRS(self._transformer.source_crs) + ) + + @property + def target_crs(self) -> CRS | None: + """ + .. versionadded:: 3.3.0 + + Returns + ------- + CRS | None: + The target CRS of a CoordinateOperation. + """ + return ( + None + if self._transformer.target_crs is None + else CRS(self._transformer.target_crs) + ) + +
+[docs] + @staticmethod + def from_proj( + proj_from: Any, + proj_to: Any, + always_xy: bool = False, + area_of_interest: AreaOfInterest | None = None, + ) -> "Transformer": + """Make a Transformer from a :obj:`pyproj.Proj` or input used to create one. + + .. deprecated:: 3.4.1 :meth:`~Transformer.from_crs` is preferred. + + .. versionadded:: 2.2.0 always_xy + .. versionadded:: 2.3.0 area_of_interest + + Parameters + ---------- + proj_from: :obj:`pyproj.Proj` or input used to create one + Projection of input data. + proj_to: :obj:`pyproj.Proj` or input used to create one + Projection of output data. + always_xy: bool, default=False + If true, the transform method will accept as input and return as output + coordinates using the traditional GIS order, that is longitude, latitude + for geographic CRS and easting, northing for most projected CRS. + area_of_interest: :class:`.AreaOfInterest`, optional + The area of interest to help select the transformation. + + Returns + ------- + Transformer + + """ + # pylint: disable=import-outside-toplevel + from pyproj import Proj + + if not isinstance(proj_from, Proj): + proj_from = Proj(proj_from) + if not isinstance(proj_to, Proj): + proj_to = Proj(proj_to) + + return Transformer.from_crs( + proj_from.crs, + proj_to.crs, + always_xy=always_xy, + area_of_interest=area_of_interest, + )
+ + +
+[docs] + @staticmethod + def from_crs( + crs_from: Any, + crs_to: Any, + always_xy: bool = False, + area_of_interest: AreaOfInterest | None = None, + authority: str | None = None, + accuracy: float | None = None, + allow_ballpark: bool | None = None, + force_over: bool = False, + only_best: bool | None = None, + ) -> "Transformer": + """Make a Transformer from a :obj:`pyproj.crs.CRS` or input used to create one. + + See: + + - :c:func:`proj_create_crs_to_crs` + - :c:func:`proj_create_crs_to_crs_from_pj` + + .. versionadded:: 2.2.0 always_xy + .. versionadded:: 2.3.0 area_of_interest + .. versionadded:: 3.1.0 authority, accuracy, allow_ballpark + .. versionadded:: 3.4.0 force_over + .. versionadded:: 3.5.0 only_best + + Parameters + ---------- + crs_from: pyproj.crs.CRS or input used to create one + Projection of input data. + crs_to: pyproj.crs.CRS or input used to create one + Projection of output data. + always_xy: bool, default=False + If true, the transform method will accept as input and return as output + coordinates using the traditional GIS order, that is longitude, latitude + for geographic CRS and easting, northing for most projected CRS. + area_of_interest: :class:`.AreaOfInterest`, optional + The area of interest to help select the transformation. + authority: str, optional + When not specified, coordinate operations from any authority will be + searched, with the restrictions set in the + authority_to_authority_preference database table related to the + authority of the source/target CRS themselves. If authority is set + to “any”, then coordinate operations from any authority will be + searched. If authority is a non-empty string different from "any", + then coordinate operations will be searched only in that authority + namespace (e.g. EPSG). + accuracy: float, optional + The minimum desired accuracy (in metres) of the candidate + coordinate operations. + allow_ballpark: bool, optional + Set to False to disallow the use of Ballpark transformation + in the candidate coordinate operations. Default is to allow. + force_over: bool, default=False + If True, it will to force the +over flag on the transformation. + Requires PROJ 9+. + only_best: bool, optional + Can be set to True to cause PROJ to error out if the best + transformation known to PROJ and usable by PROJ if all grids known and + usable by PROJ were accessible, cannot be used. Best transformation should + be understood as the transformation returned by + :c:func:`proj_get_suggested_operation` if all known grids were + accessible (either locally or through network). + Note that the default value for this option can be also set with the + :envvar:`PROJ_ONLY_BEST_DEFAULT` environment variable, or with the + ``only_best_default`` setting of :ref:`proj-ini`. + The only_best kwarg overrides the default value if set. + Requires PROJ 9.2+. + + Returns + ------- + Transformer + + """ + return Transformer( + TransformerFromCRS( + cstrencode(CRS.from_user_input(crs_from).srs), + cstrencode(CRS.from_user_input(crs_to).srs), + always_xy=always_xy, + area_of_interest=area_of_interest, + authority=authority, + accuracy=accuracy if accuracy is None else str(accuracy), + allow_ballpark=allow_ballpark, + force_over=force_over, + only_best=only_best, + ) + )
+ + +
+[docs] + @staticmethod + def from_pipeline(proj_pipeline: str) -> "Transformer": + """Make a Transformer from a PROJ pipeline string. + + :ref:`pipeline` + + See: + + - :c:func:`proj_create` + - :c:func:`proj_create_from_database` + + .. versionadded:: 3.1.0 AUTH:CODE string support (e.g. EPSG:1671) + + Allowed input: + - a PROJ string + - a WKT string + - a PROJJSON string + - an object code (e.g. "EPSG:1671" + "urn:ogc:def:coordinateOperation:EPSG::1671") + - an object name. e.g "ITRF2014 to ETRF2014 (1)". + In that case as uniqueness is not guaranteed, + heuristics are applied to determine the appropriate best match. + - a OGC URN combining references for concatenated operations + (e.g. "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895, + coordinateOperation:EPSG::1618") + + Parameters + ---------- + proj_pipeline: str + Projection pipeline string. + + Returns + ------- + Transformer + + """ + return Transformer(TransformerFromPipeline(cstrencode(proj_pipeline)))
+ + + @overload + def transform( # noqa: E704 pylint: disable=invalid-name + self, + xx: Any, + yy: Any, + radians: bool = False, + errcheck: bool = False, + direction: TransformDirection | str = TransformDirection.FORWARD, + inplace: bool = False, + ) -> tuple[Any, Any]: ... + + @overload + def transform( # noqa: E704 pylint: disable=invalid-name + self, + xx: Any, + yy: Any, + zz: Any, + radians: bool = False, + errcheck: bool = False, + direction: TransformDirection | str = TransformDirection.FORWARD, + inplace: bool = False, + ) -> tuple[Any, Any, Any]: ... + + @overload + def transform( # noqa: E704 pylint: disable=invalid-name + self, + xx: Any, + yy: Any, + zz: Any, + tt: Any, + radians: bool = False, + errcheck: bool = False, + direction: TransformDirection | str = TransformDirection.FORWARD, + inplace: bool = False, + ) -> tuple[Any, Any, Any, Any]: ... + +
+[docs] + def transform( # pylint: disable=invalid-name + self, + xx, + yy, + zz=None, + tt=None, + radians=False, + errcheck=False, + direction=TransformDirection.FORWARD, + inplace=False, + ): + """ + Transform points between two coordinate systems. + + See: :c:func:`proj_trans_generic` + + .. versionadded:: 2.1.1 errcheck + .. versionadded:: 2.2.0 direction + .. versionadded:: 3.2.0 inplace + + Accepted numeric scalar or array: + + - :class:`int` + - :class:`float` + - :class:`numpy.floating` + - :class:`numpy.integer` + - :class:`list` + - :class:`tuple` + - :class:`array.array` + - :class:`numpy.ndarray` + - :class:`xarray.DataArray` + - :class:`pandas.Series` + + Parameters + ---------- + xx: scalar or array + Input x coordinate(s). + yy: scalar or array + Input y coordinate(s). + zz: scalar or array, optional + Input z coordinate(s). + tt: scalar or array, optional + Input time coordinate(s). + radians: bool, default=False + If True, will expect input data to be in radians and will return radians + if the projection is geographic. Otherwise, it uses degrees. + Ignored for pipeline transformations with pyproj 2, + but will work in pyproj 3. + errcheck: bool, default=False + If True, an exception is raised if the errors are found in the process. + If False, ``inf`` is returned for errors. + direction: pyproj.enums.TransformDirection, optional + The direction of the transform. + Default is :attr:`pyproj.enums.TransformDirection.FORWARD`. + inplace: bool, default=False + If True, will attempt to write the results to the input array + instead of returning a new array. This will fail if the input + is not an array in C order with the double data type. + + Example + -------- + + >>> from pyproj import Transformer + >>> transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857") + >>> x3, y3 = transformer.transform(33, 98) + >>> f"{x3:.3f} {y3:.3f}" + '10909310.098 3895303.963' + >>> pipeline_str = ( + ... "+proj=pipeline +step +proj=longlat +ellps=WGS84 " + ... "+step +proj=unitconvert +xy_in=rad +xy_out=deg" + ... ) + >>> pipe_trans = Transformer.from_pipeline(pipeline_str) + >>> xt, yt = pipe_trans.transform(2.1, 0.001) + >>> f"{xt:.3f} {yt:.3f}" + '2.100 0.001' + >>> transproj = Transformer.from_crs( + ... {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'}, + ... "EPSG:4326", + ... always_xy=True, + ... ) + >>> xpj, ypj, zpj = transproj.transform( + ... -2704026.010, + ... -4253051.810, + ... 3895878.820, + ... radians=True, + ... ) + >>> f"{xpj:.3f} {ypj:.3f} {zpj:.3f}" + '-2.137 0.661 -20.531' + >>> transprojr = Transformer.from_crs( + ... "EPSG:4326", + ... {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'}, + ... always_xy=True, + ... ) + >>> xpjr, ypjr, zpjr = transprojr.transform(xpj, ypj, zpj, radians=True) + >>> f"{xpjr:.3f} {ypjr:.3f} {zpjr:.3f}" + '-2704026.010 -4253051.810 3895878.820' + >>> transformer = Transformer.from_crs("EPSG:4326", 4326) + >>> xeq, yeq = transformer.transform(33, 98) + >>> f"{xeq:.0f} {yeq:.0f}" + '33 98' + + """ + try: + # function optimized for point data + return self._transformer._transform_point( + inx=xx, + iny=yy, + inz=zz, + intime=tt, + direction=direction, + radians=radians, + errcheck=errcheck, + ) + except TypeError: + pass + # process inputs, making copies that support buffer API. + inx, x_data_type = _copytobuffer(xx, inplace=inplace) + iny, y_data_type = _copytobuffer(yy, inplace=inplace) + if zz is not None: + inz, z_data_type = _copytobuffer(zz, inplace=inplace) + else: + inz = None + if tt is not None: + intime, t_data_type = _copytobuffer(tt, inplace=inplace) + else: + intime = None + # call pj_transform. inx,iny,inz buffers modified in place. + self._transformer._transform( + inx=inx, + iny=iny, + inz=inz, + intime=intime, + direction=direction, + radians=radians, + errcheck=errcheck, + ) + # if inputs were lists, tuples or floats, convert back. + outx = _convertback(x_data_type, inx) + outy = _convertback(y_data_type, iny) + return_data: tuple[Any, ...] = (outx, outy) + if zz is not None: + return_data += (_convertback(z_data_type, inz),) + if tt is not None: + return_data += (_convertback(t_data_type, intime),) + return return_data
+ + +
+[docs] + def itransform( + self, + points: Any, + switch: bool = False, + time_3rd: bool = False, + radians: bool = False, + errcheck: bool = False, + direction: TransformDirection | str = TransformDirection.FORWARD, + ) -> Iterator[Iterable]: + """ + Iterator/generator version of the function pyproj.Transformer.transform. + + See: :c:func:`proj_trans_generic` + + .. versionadded:: 2.1.1 errcheck + .. versionadded:: 2.2.0 direction + + Parameters + ---------- + points: list + List of point tuples. + switch: bool, default=False + If True x, y or lon,lat coordinates of points are switched to y, x + or lat, lon. Default is False. + time_3rd: bool, default=False + If the input coordinates are 3 dimensional and the 3rd dimension is time. + radians: bool, default=False + If True, will expect input data to be in radians and will return radians + if the projection is geographic. Otherwise, it uses degrees. + Ignored for pipeline transformations with pyproj 2, + but will work in pyproj 3. + errcheck: bool, default=False + If True, an exception is raised if the errors are found in the process. + If False, ``inf`` is returned for errors. + direction: pyproj.enums.TransformDirection, optional + The direction of the transform. + Default is :attr:`pyproj.enums.TransformDirection.FORWARD`. + + + Example + -------- + + >>> from pyproj import Transformer + >>> transformer = Transformer.from_crs(4326, 2100) + >>> points = [(22.95, 40.63), (22.81, 40.53), (23.51, 40.86)] + >>> for pt in transformer.itransform(points): '{:.3f} {:.3f}'.format(*pt) + '2221638.801 2637034.372' + '2212924.125 2619851.898' + '2238294.779 2703763.736' + >>> pipeline_str = ( + ... "+proj=pipeline +step +proj=longlat +ellps=WGS84 " + ... "+step +proj=unitconvert +xy_in=rad +xy_out=deg" + ... ) + >>> pipe_trans = Transformer.from_pipeline(pipeline_str) + >>> for pt in pipe_trans.itransform([(2.1, 0.001)]): + ... '{:.3f} {:.3f}'.format(*pt) + '2.100 0.001' + >>> transproj = Transformer.from_crs( + ... {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'}, + ... "EPSG:4326", + ... always_xy=True, + ... ) + >>> for pt in transproj.itransform( + ... [(-2704026.010, -4253051.810, 3895878.820)], + ... radians=True, + ... ): + ... '{:.3f} {:.3f} {:.3f}'.format(*pt) + '-2.137 0.661 -20.531' + >>> transprojr = Transformer.from_crs( + ... "EPSG:4326", + ... {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'}, + ... always_xy=True, + ... ) + >>> for pt in transprojr.itransform( + ... [(-2.137, 0.661, -20.531)], + ... radians=True + ... ): + ... '{:.3f} {:.3f} {:.3f}'.format(*pt) + '-2704214.394 -4254414.478 3894270.731' + >>> transproj_eq = Transformer.from_crs( + ... 'EPSG:4326', + ... '+proj=longlat +datum=WGS84 +no_defs +type=crs', + ... always_xy=True, + ... ) + >>> for pt in transproj_eq.itransform([(-2.137, 0.661)]): + ... '{:.3f} {:.3f}'.format(*pt) + '-2.137 0.661' + + """ + point_it = iter(points) # point iterator + # get first point to check stride + try: + fst_pt = next(point_it) + except StopIteration: + raise ValueError("iterable must contain at least one point") from None + + stride = len(fst_pt) + if stride not in (2, 3, 4): + raise ValueError("points can contain up to 4 coordinates") + + if time_3rd and stride != 3: + raise ValueError("'time_3rd' is only valid for 3 coordinates.") + + # create a coordinate sequence generator etc. x1,y1,z1,x2,y2,z2,.... + # chain so the generator returns the first point that was already acquired + coord_gen = chain( + fst_pt, (coords[c] for coords in point_it for c in range(stride)) + ) + + while True: + # create a temporary buffer storage for + # the next 64 points (64*stride*8 bytes) + buff = array("d", islice(coord_gen, 0, 64 * stride)) + if len(buff) == 0: + break + + self._transformer._transform_sequence( + stride, + buff, + switch=switch, + direction=direction, + time_3rd=time_3rd, + radians=radians, + errcheck=errcheck, + ) + + yield from zip(*([iter(buff)] * stride))
+ + +
+[docs] + def transform_bounds( + self, + left: float, + bottom: float, + right: float, + top: float, + densify_pts: int = 21, + radians: bool = False, + errcheck: bool = False, + direction: TransformDirection | str = TransformDirection.FORWARD, + ) -> tuple[float, float, float, float]: + """ + .. versionadded:: 3.1.0 + + See: :c:func:`proj_trans_bounds` + + Transform boundary densifying the edges to account for nonlinear + transformations along these edges and extracting the outermost bounds. + + If the destination CRS is geographic and right < left then the bounds + crossed the antimeridian. In this scenario there are two polygons, + one on each side of the antimeridian. The first polygon should be + constructed with (left, bottom, 180, top) and the second with + (-180, bottom, top, right). + + To construct the bounding polygons with shapely:: + + def bounding_polygon(left, bottom, right, top): + if right < left: + return shapely.geometry.MultiPolygon( + [ + shapely.geometry.box(left, bottom, 180, top), + shapely.geometry.box(-180, bottom, right, top), + ] + ) + return shapely.geometry.box(left, bottom, right, top) + + + Parameters + ---------- + left: float + Minimum bounding coordinate of the first axis in source CRS + (or the target CRS if using the reverse direction). + bottom: float + Minimum bounding coordinate of the second axis in source CRS. + (or the target CRS if using the reverse direction). + right: float + Maximum bounding coordinate of the first axis in source CRS. + (or the target CRS if using the reverse direction). + top: float + Maximum bounding coordinate of the second axis in source CRS. + (or the target CRS if using the reverse direction). + densify_points: uint, default=21 + Number of points to add to each edge to account for nonlinear edges + produced by the transform process. Large numbers will produce worse + performance. + radians: bool, default=False + If True, will expect input data to be in radians and will return radians + if the projection is geographic. Otherwise, it uses degrees. + errcheck: bool, default=False + If True, an exception is raised if the errors are found in the process. + If False, ``inf`` is returned for errors. + direction: pyproj.enums.TransformDirection, optional + The direction of the transform. + Default is :attr:`pyproj.enums.TransformDirection.FORWARD`. + + Returns + ------- + left, bottom, right, top: float + Outermost coordinates in target coordinate reference system. + """ + return self._transformer._transform_bounds( + left=left, + bottom=bottom, + right=right, + top=top, + densify_pts=densify_pts, + radians=radians, + errcheck=errcheck, + direction=direction, + )
+ + +
+[docs] + def to_proj4( + self, + version: ProjVersion | str = ProjVersion.PROJ_5, + pretty: bool = False, + ) -> str: + """ + Convert the projection to a PROJ string. + + .. versionadded:: 3.1.0 + + Parameters + ---------- + version: pyproj.enums.ProjVersion + The version of the PROJ string output. + Default is :attr:`pyproj.enums.ProjVersion.PROJ_5`. + pretty: bool, default=False + If True, it will set the output to be a multiline string. + + Returns + ------- + str: + The PROJ string. + + """ + return self._transformer.to_proj4(version=version, pretty=pretty)
+ + +
+[docs] + def to_wkt( + self, + version: WktVersion | str = WktVersion.WKT2_2019, + pretty: bool = False, + ) -> str: + """ + Convert the projection to a WKT string. + + Version options: + - WKT2_2015 + - WKT2_2015_SIMPLIFIED + - WKT2_2019 + - WKT2_2019_SIMPLIFIED + - WKT1_GDAL + - WKT1_ESRI + + + Parameters + ---------- + version: pyproj.enums.WktVersion, optional + The version of the WKT output. + Default is :attr:`pyproj.enums.WktVersion.WKT2_2019`. + pretty: bool, default=False + If True, it will set the output to be a multiline string. + + Returns + ------- + str: + The WKT string. + """ + return self._transformer.to_wkt(version=version, pretty=pretty)
+ + +
+[docs] + def to_json(self, pretty: bool = False, indentation: int = 2) -> str: + """ + Convert the projection to a JSON string. + + .. versionadded:: 2.4.0 + + Parameters + ---------- + pretty: bool, default=False + If True, it will set the output to be a multiline string. + indentation: int, default=2 + If pretty is True, it will set the width of the indentation. + + Returns + ------- + str: + The JSON string. + """ + return self._transformer.to_json(pretty=pretty, indentation=indentation)
+ + +
+[docs] + def to_json_dict(self) -> dict: + """ + Convert the projection to a JSON dictionary. + + .. versionadded:: 2.4.0 + + Returns + ------- + dict: + The JSON dictionary. + """ + return self._transformer.to_json_dict()
+ + + def __str__(self) -> str: + return self.definition + + def __repr__(self) -> str: + return ( + f"<{self._transformer.type_name}: {self.name}>\n" + f"Description: {self.description}\n" + f"Area of Use:\n{self.area_of_use or '- undefined'}" + ) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Transformer): + return False + return self._transformer.__eq__(other._transformer) + +
+[docs] + def is_exact_same(self, other: Any) -> bool: + """ + Check if the Transformer objects are the exact same. + If it is not a Transformer, then it returns False. + + Parameters + ---------- + other: Any + + Returns + ------- + bool + """ + if not isinstance(other, Transformer): + return False + return self._transformer.is_exact_same(other._transformer)
+
+ + + +
+[docs] +def transform( # pylint: disable=invalid-name + p1: Any, + p2: Any, + x: Any, + y: Any, + z: Any | None = None, + tt: Any | None = None, + radians: bool = False, + errcheck: bool = False, + always_xy: bool = False, +): + """ + .. versionadded:: 2.2.0 always_xy + + .. deprecated:: 2.6.1 + This function is deprecated. See: :ref:`upgrade_transformer` + + x2, y2, z2 = transform(p1, p2, x1, y1, z1) + + Transform points between two coordinate systems defined by the + Proj instances p1 and p2. + + The points x1,y1,z1 in the coordinate system defined by p1 are + transformed to x2,y2,z2 in the coordinate system defined by p2. + + z1 is optional, if it is not set it is assumed to be zero (and + only x2 and y2 are returned). If the optional keyword + 'radians' is True (default is False), then all input and + output coordinates will be in radians instead of the default + of degrees for geographic input/output projections. + If the optional keyword 'errcheck' is set to True an + exception is raised if the transformation is + invalid. By default errcheck=False and ``inf`` is returned for an + invalid transformation (and no exception is raised). + If `always_xy` is toggled, the transform method will accept as + input and return as output coordinates using the traditional GIS order, + that is longitude, latitude for geographic CRS and easting, + northing for most projected CRS. + + In addition to converting between cartographic and geographic + projection coordinates, this function can take care of datum + shifts (which cannot be done using the __call__ method of the + Proj instances). It also allows for one of the coordinate + systems to be geographic (proj = 'latlong'). + + x,y and z can be numpy or regular python arrays, python + lists/tuples or scalars. Arrays are fastest. For projections in + geocentric coordinates, values of x and y are given in meters. + z is always meters. + + """ + warnings.warn( + ( + "This function is deprecated. " + "See: https://pyproj4.github.io/pyproj/stable/" + "gotchas.html#upgrading-to-pyproj-2-from-pyproj-1" + ), + FutureWarning, + stacklevel=2, + ) + return Transformer.from_proj(p1, p2, always_xy=always_xy).transform( + xx=x, yy=y, zz=z, tt=tt, radians=radians, errcheck=errcheck + )
+ + + +
+[docs] +def itransform( # pylint: disable=invalid-name + p1: Any, + p2: Any, + points: Iterable[Iterable], + switch: bool = False, + time_3rd: bool = False, + radians: bool = False, + errcheck: bool = False, + always_xy: bool = False, +): + """ + .. versionadded:: 2.2.0 always_xy + + .. deprecated:: 2.6.1 + This function is deprecated. See: :ref:`upgrade_transformer` + + points2 = itransform(p1, p2, points1) + Iterator/generator version of the function pyproj.transform. + Transform points between two coordinate systems defined by the + Proj instances p1 and p2. This function can be used as an alternative + to pyproj.transform when there is a need to transform a big number of + coordinates lazily, for example when reading and processing from a file. + Points1 is an iterable/generator of coordinates x1,y1(,z1) or lon1,lat1(,z1) + in the coordinate system defined by p1. Points2 is an iterator that returns tuples + of x2,y2(,z2) or lon2,lat2(,z2) coordinates in the coordinate system defined by p2. + z are provided optionally. + + Points1 can be: + - a tuple/list of tuples/lists i.e. for 2d points: [(xi,yi),(xj,yj),....(xn,yn)] + - a Nx3 or Nx2 2d numpy array where N is the point number + - a generator of coordinates (xi,yi) for 2d points or (xi,yi,zi) for 3d + + If optional keyword 'switch' is True (default is False) then x, y or lon,lat + coordinates of points are switched to y, x or lat, lon. + If the optional keyword 'radians' is True (default is False), + then all input and output coordinates will be in radians instead + of the default of degrees for geographic input/output projections. + If the optional keyword 'errcheck' is set to True an + exception is raised if the transformation is + invalid. By default errcheck=False and ``inf`` is returned for an + invalid transformation (and no exception is raised). + If `always_xy` is toggled, the transform method will accept as + input and return as output coordinates using the traditional GIS order, + that is longitude, latitude for geographic CRS and easting, northing + for most projected CRS. + + + Example usage: + + >>> from pyproj import Proj, itransform + >>> # projection 1: WGS84 + >>> # (defined by epsg code 4326) + >>> p1 = Proj('epsg:4326', preserve_units=False) + >>> # projection 2: GGRS87 / Greek Grid + >>> p2 = Proj('epsg:2100', preserve_units=False) + >>> # Three points with coordinates lon, lat in p1 + >>> points = [(22.95, 40.63), (22.81, 40.53), (23.51, 40.86)] + >>> # transform this point to projection 2 coordinates. + >>> for pt in itransform(p1,p2,points, always_xy=True): '%6.3f %7.3f' % pt + '411050.470 4497928.574' + '399060.236 4486978.710' + '458553.243 4523045.485' + >>> for pt in itransform(4326, 4326, [(30, 60)]): + ... '{:.0f} {:.0f}'.format(*pt) + '30 60' + + """ + warnings.warn( + ( + "This function is deprecated. " + "See: https://pyproj4.github.io/pyproj/stable/" + "gotchas.html#upgrading-to-pyproj-2-from-pyproj-1" + ), + FutureWarning, + stacklevel=2, + ) + return Transformer.from_proj(p1, p2, always_xy=always_xy).itransform( + points, switch=switch, time_3rd=time_3rd, radians=radians, errcheck=errcheck + )
+ +
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/3.7.0/_sources/advanced_examples.rst.txt b/3.7.0/_sources/advanced_examples.rst.txt new file mode 100644 index 000000000..cfd0e1a2f --- /dev/null +++ b/3.7.0/_sources/advanced_examples.rst.txt @@ -0,0 +1,375 @@ +.. _advanced_examples: + +Advanced Examples +================= + +Optimize Transformations +------------------------ + +Here are a few tricks to try out if you want to optimize your transformations. + + +Repeated transformations +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.1.0 + +If you use the same transform, using the :class:`pyproj.transformer.Transformer` can help +optimize your transformations. + +.. code-block:: python + + import numpy + from pyproj import Transformer, transform + + transformer = Transformer.from_crs(2263, 4326) + x_coords = numpy.random.randint(80000, 120000) + y_coords = numpy.random.randint(200000, 250000) + + +Example with :func:`pyproj.transformer.transform`: + +.. code-block:: python + + transform(2263, 4326, x_coords, y_coords) + +Results: 160 ms ± 3.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) + +Example with :class:`pyproj.transformer.Transformer`: + +.. code-block:: python + + transformer.transform(x_coords, y_coords) + +Results: 6.32 µs ± 49.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) + + +Transforming with the same projections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +pyproj skips `noop` transformations. + + +Transformation Group +-------------------- + +.. versionadded:: 2.3.0 + +The :class:`pyproj.transformer.TransformerGroup` provides both available +transformations as well as missing transformations. + +1. Helpful if you want to use an alternate transformation and have a good reason for it. + +.. code-block:: python + + >>> from pyproj.transformer import TransformerGroup + >>> trans_group = TransformerGroup("EPSG:4326","EPSG:2964") + >>> trans_group + + - transformers: 8 + - unavailable_operations: 1 + >>> trans_group.best_available + True + >>> trans_group.transformers[0].transform(66, -153) + (149661.2825058747, 5849322.174897663) + >>> trans_group.transformers[1].transform(66, -153) + (149672.928811047, 5849311.372139239) + >>> trans_group.transformers[2].transform(66, -153) + (149748.32734832275, 5849274.621409136) + + +2. Helpful if want to check that the best possible transformation exists. + And if not, how to get the missing grid. + + +.. code-block:: python + + >>> from pyproj.transformer import TransformerGroup + >>> tg = TransformerGroup("EPSG:4326", "+proj=aea +lat_0=50 +lon_0=-154 +lat_1=55 +lat_2=65 +x_0=0 +y_0=0 +datum=NAD27 +no_defs +type=crs +units=m", always_xy=True) + UserWarning: Best transformation is not available due to missing Grid(short_name=ntv2_0.gsb, full_name=, package_name=proj-datumgrid-north-america, url=https://download.osgeo.org/proj/proj-datumgrid-north-america-latest.zip, direct_download=True, open_license=True, available=False) + f"{operation.grids[0]!r}" + >>> tg + + - transformers: 37 + - unavailable_operations: 41 + >>> tg.transformers[0].description + 'axis order change (2D) + Inverse of NAD27 to WGS 84 (3) + axis order change (2D) + unknown' + >>> tg.unavailable_operations[0].name + 'Inverse of NAD27 to WGS 84 (33) + axis order change (2D) + unknown' + >>> tg.unavailable_operations[0].grids[0].url + 'https://download.osgeo.org/proj/proj-datumgrid-north-america-latest.zip' + + +Area of Interest +---------------- + +.. versionadded:: 2.3.0 + +Depending on the location of your transformation, using the area of interest may impact +which transformation operation is selected in the transformation. + +.. code-block:: python + + >>> from pyproj.transformer import Transformer, AreaOfInterest + >>> transformer = Transformer.from_crs("EPSG:4326", "EPSG:2694") + >>> transformer + + Description: Inverse of Pulkovo 1995 to WGS 84 (2) + 3-degree Gauss-Kruger zone 60 + Area of Use: + - name: Russia + - bounds: (18.92, 39.87, -168.97, 85.2) + >>> transformer = Transformer.from_crs( + ... "EPSG:4326", + ... "EPSG:2694", + ... area_of_interest=AreaOfInterest(-136.46, 49.0, -60.72, 83.17), + ... ) + >>> transformer + + Description: Inverse of NAD27 to WGS 84 (13) + Alaska Albers + Area of Use: + - name: Canada - NWT; Nunavut; Saskatchewan + - bounds: (-136.46, 49.0, -60.72, 83.17) + + +Promote CRS to 3D +------------------- + +.. versionadded:: 3.1 + + +In PROJ 6+ you need to explicitly change your CRS to 3D if you have +2D CRS and you want the ellipsoidal height taken into account. + + +.. code-block:: python + + >>> from pyproj import CRS, Transformer + >>> transformer = Transformer.from_crs("EPSG:4326", "EPSG:2056", always_xy=True) + >>> transformer.transform(8.37909, 47.01987, 1000) + (2671499.8913080636, 1208075.1135782297, 1000.0) + >>> transformer_3d = Transformer.from_crs( + ... CRS("EPSG:4326").to_3d(), + ... CRS("EPSG:2056").to_3d(), + ... always_xy=True, + ...) + >>> transformer_3d.transform(8.37909, 47.01987, 1000) + (2671499.8913080636, 1208075.1135782297, 951.4265527743846) + + +Demote CRS to 2D +---------------- + +.. versionadded:: 3.6 + + +With the need for explicit 3D CRS since PROJ 6+, one might need to retrieve their 2D version, +for example to create another 3D CRS compound between a 2D CRS and a vertical CRS. + +.. code-block:: python + + >>> from pyproj import CRS, Transformer + >>> from pyproj.crs import CompoundCRS + >>> src_crs = CRS("EPSG:4979") # Any 3D CRS, here the 3D WGS 84 + >>> vert_crs = CRS("EPSG:5773") # Any vertical CRS, here the EGM96 geoid + >>> dst_crs = CompoundCRS(src_crs.name + vert_crs.name, components=[src_crs.to_2d(), vert_crs]) + >>> transformer_3d = Transformer.from_crs(src_crs, dst_crs, always_xy=True) + >>> transformer_3d.transform(8.37909, 47.01987, 1000) + (8.37909, 47.01987, 951.7851086745321) + + +Projected CRS Bounds +---------------------- + +.. versionadded:: 3.1 + +The boundary of the CRS is given in geographic coordinates. +This is the recommended method for calculating the projected bounds. + +.. code-block:: python + + >>> from pyproj import CRS, Transformer + >>> crs = CRS("EPSG:3857") + >>> transformer = Transformer.from_crs(crs.geodetic_crs, crs, always_xy=True) + >>> transformer.transform_bounds(*crs.area_of_use.bounds) + (-20037508.342789244, -20048966.104014594, 20037508.342789244, 20048966.104014594) + + +Multithreading +-------------- + +As of version 3.1, these objects are thread-safe: + +- :class:`pyproj.crs.CRS` +- :class:`pyproj.transformer.Transformer` + +If you have pyproj<3.1, you will need to create the object +within the thread that uses it. + +Here is a simple demonstration: + +.. code-block:: python + + import concurrent.futures + + from pyproj import Transformer + + + def transform_point(point): + transformer = Transformer.from_crs(4326, 3857) + return transformer.transform(point, point * 2) + + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + for result in executor.map(transform_point, range(5)): + print(result) + + +Optimizing Single-Threaded Applications +---------------------------------------- + +If you have a single-threaded application that generates many objects, +enabling the use of the global context can provide performance enhancements. + +For information about using the global context, see: :ref:`global_context` + +Here is an example where enabling the global context can help: + +.. code-block:: python + + import pyproj + + codes = pyproj.get_codes("EPSG", pyproj.enums.PJType.PROJECTED_CRS, False) + crs_list = [pyproj.CRS.from_epsg(code) for code in codes] + + +Caching pyproj objects +----------------------- + +If you are likely to re-create pyproj objects such as :class:`pyproj.transformer.Transformer` +or :class:`pyproj.crs.CRS`, using a cache can help reduce the cost +of re-creating the objects. + +Transformer +~~~~~~~~~~~~ + +.. code-block:: python + + from functools import lru_cache + + from pyproj import Transformer + + TransformerFromCRS = lru_cache(Transformer.from_crs) + + Transformer.from_crs(2263, 4326) # no cache + TransformerFromCRS(2263, 4326) # cache + + +Try it: + +.. code-block:: python + + from timeit import timeit + + timeit( + "CachedTransformer(2263, 4326)", + setup=( + "from pyproj import Transformer; " + "from functools import lru_cache; " + "CachedTransformer = lru_cache(Transformer.from_crs)" + ), + number=1000000, + ) + + timeit( + "Transformer.from_crs(2263, 4326)", + setup=("from pyproj import Transformer"), + number=100, + ) + + +Without the cache, it takes around 2 seconds to do 100 iterations. With the cache, +it takes 0.1 seconds to do 1 million iterations. + + +CRS Example +~~~~~~~~~~~~ + +.. code-block:: python + + + from functools import lru_cache + + from pyproj import CRS + + CachedCRS = lru_cache(CRS) + + crs = CRS(4326) # no cache + crs = CachedCRS(4326) # cache + + +Try it: + +.. code-block:: python + + from timeit import timeit + + timeit( + "CachedCRS(4326)", + setup=( + "from pyproj import CRS; " + "from functools import lru_cache; " + "CachedCRS = lru_cache(CRS)" + ), + number=1000000, + ) + + timeit( + "CRS(4326)", + setup=("from pyproj import CRS"), + number=1000, + ) + + +Without the cache, it takes around 1 seconds to do 1000 iterations. With the cache, +it takes 0.1 seconds to do 1 million iterations. + + +.. _debugging-internal-proj: + +Debugging Internal PROJ +------------------------ + +.. versionadded:: 3.0.0 + +To get more debugging information from the internal PROJ code: + +1. Set the :envvar:`PROJ_DEBUG` + environment variable to the desired level. + +2. Activate logging in `pyproj` with the devel `DEBUG`: + + More information available here: https://docs.python.org/3/howto/logging.html + + Here are examples to get started. + + Add handler to the `pyproj` logger: + + .. code-block:: python + + import logging + + console_handler = logging.StreamHandler() + formatter = logging.Formatter("%(levelname)s:%(message)s") + console_handler.setFormatter(formatter) + logger = logging.getLogger("pyproj") + logger.addHandler(console_handler) + logger.setLevel(logging.DEBUG) + + + Activate default logging config: + + .. code-block:: python + + import logging + + logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG) diff --git a/3.7.0/_sources/api/aoi.rst.txt b/3.7.0/_sources/api/aoi.rst.txt new file mode 100644 index 000000000..1a314e523 --- /dev/null +++ b/3.7.0/_sources/api/aoi.rst.txt @@ -0,0 +1,24 @@ +Area of Interest +================== + +pyproj.aoi.AreaOfInterest +-------------------------- + +.. note:: The backwards compatible import is `pyproj.transformer.AreaOfInterest` + +.. autoclass:: pyproj.aoi.AreaOfInterest + :members: + + +pyproj.aoi.AreaOfUse +--------------------- + +.. autoclass:: pyproj.aoi.AreaOfUse + :members: + + +pyproj.aoi.BBox +----------------- + +.. autoclass:: pyproj.aoi.BBox + :members: diff --git a/3.7.0/_sources/api/crs/coordinate_operation.rst.txt b/3.7.0/_sources/api/crs/coordinate_operation.rst.txt new file mode 100644 index 000000000..76a47211f --- /dev/null +++ b/3.7.0/_sources/api/crs/coordinate_operation.rst.txt @@ -0,0 +1,232 @@ +.. _coordinate_operation: + +Coordinate Operations +===================== + +CoordinateOperation +-------------------- +.. autoclass:: pyproj.crs.CoordinateOperation + :members: + :inherited-members: + + +Param +------ + +.. autoclass:: pyproj._crs.Param + :members: + +Grid +---- + +.. autoclass:: pyproj._crs.Grid + :members: + + +AlbersEqualAreaConversion +--------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.AlbersEqualAreaConversion + :members: + :show-inheritance: + :special-members: __new__ + + +AzimuthalEquidistantConversion +------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.AzimuthalEquidistantConversion + :members: + :show-inheritance: + :special-members: __new__ + + +EquidistantCylindricalConversion +-------------------------------- +.. autoclass:: pyproj.crs.coordinate_operation.EquidistantCylindricalConversion + :members: + :show-inheritance: + :special-members: __new__ + + +GeostationarySatelliteConversion +-------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.GeostationarySatelliteConversion + :members: + :show-inheritance: + :special-members: __new__ + + +LambertAzimuthalEqualAreaConversion +----------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.LambertAzimuthalEqualAreaConversion + :members: + :show-inheritance: + :special-members: __new__ + + +LambertConformalConic1SPConversion +----------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.LambertConformalConic1SPConversion + :members: + :show-inheritance: + :special-members: __new__ + + +LambertConformalConic2SPConversion +----------------------------------- +.. autoclass:: pyproj.crs.coordinate_operation.LambertConformalConic2SPConversion + :members: + :show-inheritance: + :special-members: __new__ + + +LambertCylindricalEqualAreaConversion +------------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.LambertCylindricalEqualAreaConversion + :members: + :show-inheritance: + :special-members: __new__ + +.. autoclass:: pyproj.crs.coordinate_operation.LambertCylindricalEqualAreaScaleConversion + + :members: + :show-inheritance: + :special-members: __new__ + + +MercatorAConversion +-------------------- +.. autoclass:: pyproj.crs.coordinate_operation.MercatorAConversion + :members: + :show-inheritance: + :special-members: __new__ + + +MercatorBConversion +------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.MercatorBConversion + :members: + :show-inheritance: + :special-members: __new__ + + +HotineObliqueMercatorBConversion +--------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.HotineObliqueMercatorBConversion + :members: + :show-inheritance: + :special-members: __new__ + + +OrthographicConversion +----------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.OrthographicConversion + :members: + :show-inheritance: + :special-members: __new__ + + +PlateCarreeConversion +-------------------------------- +.. autoclass:: pyproj.crs.coordinate_operation.PlateCarreeConversion + :members: + :show-inheritance: + :special-members: __new__ + + +PolarStereographicAConversion +----------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.PolarStereographicAConversion + :members: + :show-inheritance: + :special-members: __new__ + + +PolarStereographicBConversion +----------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.PolarStereographicBConversion + :members: + :show-inheritance: + :special-members: __new__ + + +SinusoidalConversion +--------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.SinusoidalConversion + :members: + :show-inheritance: + :special-members: __new__ + + +StereographicConversion +------------------------ + +.. autoclass:: pyproj.crs.coordinate_operation.StereographicConversion + :members: + :show-inheritance: + :special-members: __new__ + + +UTMConversion +------------- + +.. autoclass:: pyproj.crs.coordinate_operation.UTMConversion + :members: + :show-inheritance: + :special-members: __new__ + + +TransverseMercatorConversion +---------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.TransverseMercatorConversion + :members: + :show-inheritance: + :special-members: __new__ + + +VerticalPerspectiveConversion +----------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.VerticalPerspectiveConversion + :members: + :show-inheritance: + :special-members: __new__ + + +RotatedLatitudeLongitudeConversion +---------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.RotatedLatitudeLongitudeConversion + :members: + :show-inheritance: + :special-members: __new__ + + +PoleRotationNetCDFCFConversion +---------------------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.PoleRotationNetCDFCFConversion + :members: + :show-inheritance: + :special-members: __new__ + + +ToWGS84Transformation +--------------------- + +.. autoclass:: pyproj.crs.coordinate_operation.ToWGS84Transformation + :members: + :show-inheritance: + :special-members: __new__ diff --git a/3.7.0/_sources/api/crs/coordinate_system.rst.txt b/3.7.0/_sources/api/crs/coordinate_system.rst.txt new file mode 100644 index 000000000..91596a0f6 --- /dev/null +++ b/3.7.0/_sources/api/crs/coordinate_system.rst.txt @@ -0,0 +1,56 @@ +.. _coordinate_system: + +Coordinate Systems +================== + +CoordinateSystem +------------------------ + +.. autoclass:: pyproj.crs.CoordinateSystem + :members: + :inherited-members: + + +Axis +------------------------ + +.. autoclass:: pyproj._crs.Axis + :members: + :inherited-members: + + +Ellipsoidal2DCS +------------------------ + +.. autoclass:: pyproj.crs.coordinate_system.Ellipsoidal2DCS + :members: + :show-inheritance: + :special-members: __new__ + + +Ellipsoidal3DCS +------------------------ + +.. autoclass:: pyproj.crs.coordinate_system.Ellipsoidal3DCS + :members: + :show-inheritance: + :special-members: __new__ + + + +Cartesian2DCS +------------------------ + +.. autoclass:: pyproj.crs.coordinate_system.Cartesian2DCS + :members: + :show-inheritance: + :special-members: __new__ + + +VerticalCS +------------------------ + +.. autoclass:: pyproj.crs.coordinate_system.VerticalCS + :members: + :show-inheritance: + :special-members: __new__ diff --git a/3.7.0/_sources/api/crs/crs.rst.txt b/3.7.0/_sources/api/crs/crs.rst.txt new file mode 100644 index 000000000..9d834790b --- /dev/null +++ b/3.7.0/_sources/api/crs/crs.rst.txt @@ -0,0 +1,95 @@ +.. _crs: + +CRS +=== + +CRS +---- + +.. autoclass:: pyproj.crs.CRS + :members: + :inherited-members: + :special-members: __init__ + + +GeographicCRS +------------------------ + +.. autoclass:: pyproj.crs.GeographicCRS + :members: + :show-inheritance: + :special-members: __init__ + + +DerivedGeographicCRS +------------------------ + +.. autoclass:: pyproj.crs.DerivedGeographicCRS + :members: + :show-inheritance: + :special-members: __init__ + + +GeocentricCRS +------------------------ + +.. autoclass:: pyproj.crs.GeocentricCRS + :members: + :show-inheritance: + :special-members: __init__ + + +ProjectedCRS +----------------------- + +.. autoclass:: pyproj.crs.ProjectedCRS + :members: + :show-inheritance: + :special-members: __init__ + + +VerticalCRS +----------------------- + +.. autoclass:: pyproj.crs.VerticalCRS + :members: + :show-inheritance: + :special-members: __init__ + + +BoundCRS +----------------------- + +.. autoclass:: pyproj.crs.BoundCRS + :members: + :show-inheritance: + :special-members: __init__ + +CompoundCRS +----------------------- + +.. autoclass:: pyproj.crs.CompoundCRS + :members: + :show-inheritance: + :special-members: __init__ + + +CustomConstructorCRS +------------------------ + +.. autoclass:: pyproj.crs.CustomConstructorCRS + :members: + :show-inheritance: + :special-members: __init__ + + +is_wkt +----------------- + +.. autofunction:: pyproj.crs.is_wkt + + +is_proj +------------------ + +.. autofunction:: pyproj.crs.is_proj diff --git a/3.7.0/_sources/api/crs/datum.rst.txt b/3.7.0/_sources/api/crs/datum.rst.txt new file mode 100644 index 000000000..ae4066f7e --- /dev/null +++ b/3.7.0/_sources/api/crs/datum.rst.txt @@ -0,0 +1,60 @@ +.. _datum: + +Datum +===== + + +.. note:: PROJ >= 7.0.0 will have better support for aliases for datum names. + Until then, you will need to use the full name of the datum. There is support + currently for the old PROJ names for datums such as WGS84 and NAD83. + + +Datum +--------- + +.. autoclass:: pyproj.crs.Datum + :members: + :inherited-members: + + +CustomDatum +------------ + +.. autoclass:: pyproj.crs.datum.CustomDatum + :members: + :show-inheritance: + :special-members: __new__ + + +Ellipsoid +---------- + +.. autoclass:: pyproj.crs.Ellipsoid + :members: + :inherited-members: + + +CustomEllipsoid +---------------- + +.. autoclass:: pyproj.crs.datum.CustomEllipsoid + :members: + :show-inheritance: + :special-members: __new__ + + +PrimeMeridian +-------------- + +.. autoclass:: pyproj.crs.PrimeMeridian + :members: + :inherited-members: + + +CustomPrimeMeridian +-------------------- + +.. autoclass:: pyproj.crs.datum.CustomPrimeMeridian + :members: + :show-inheritance: + :special-members: __new__ diff --git a/3.7.0/_sources/api/crs/enums.rst.txt b/3.7.0/_sources/api/crs/enums.rst.txt new file mode 100644 index 000000000..80684eecd --- /dev/null +++ b/3.7.0/_sources/api/crs/enums.rst.txt @@ -0,0 +1,42 @@ +Enumerations +============ + +DatumType +---------- + +.. autoclass:: pyproj.crs.enums.DatumType + :members: + + +CoordinateOperationType +------------------------ + +.. autoclass:: pyproj.crs.enums.CoordinateOperationType + :members: + + +Cartesian2DCSAxis +------------------ + +.. autoclass:: pyproj.crs.enums.Cartesian2DCSAxis + :members: + + +Ellipsoidal2DCSAxis +-------------------- + +.. autoclass:: pyproj.crs.enums.Ellipsoidal2DCSAxis + :members: + + +Ellipsoidal3DCSAxis +-------------------- + +.. autoclass:: pyproj.crs.enums.Ellipsoidal3DCSAxis + :members: + +VerticalCSAxis +--------------- + +.. autoclass:: pyproj.crs.enums.VerticalCSAxis + :members: diff --git a/3.7.0/_sources/api/crs/index.rst.txt b/3.7.0/_sources/api/crs/index.rst.txt new file mode 100644 index 000000000..cfcc3b2f2 --- /dev/null +++ b/3.7.0/_sources/api/crs/index.rst.txt @@ -0,0 +1,12 @@ +CRS module API Documentation +============================ + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + crs + coordinate_system + coordinate_operation + datum + enums diff --git a/3.7.0/_sources/api/database.rst.txt b/3.7.0/_sources/api/database.rst.txt new file mode 100644 index 000000000..80cfab7e3 --- /dev/null +++ b/3.7.0/_sources/api/database.rst.txt @@ -0,0 +1,51 @@ +.. _database: + +Database +========= + +Methods that query the PROJ database for information. + + +pyproj.database.get_units_map +----------------------------- + +.. note:: The backwards compatible import is `pyproj.get_units_map` + +.. autofunction:: pyproj.database.get_units_map + +.. autoclass:: pyproj.database.Unit + + +pyproj.database.get_authorities +-------------------------------- + +.. note:: The backwards compatible import is `pyproj.get_authorities` + +.. autofunction:: pyproj.database.get_authorities + + +pyproj.database.get_codes +-------------------------- + +.. note:: The backwards compatible import is `pyproj.get_codes` + +.. autofunction:: pyproj.database.get_codes + + +pyproj.database.query_crs_info +------------------------------- + +.. autofunction:: pyproj.database.query_crs_info + +.. autoclass:: pyproj.database.CRSInfo + +pyproj.database.query_utm_crs_info +----------------------------------- + +.. autofunction:: pyproj.database.query_utm_crs_info + + +pyproj.database.get_database_metadata +--------------------------------------- + +.. autofunction:: pyproj.database.get_database_metadata diff --git a/3.7.0/_sources/api/datadir.rst.txt b/3.7.0/_sources/api/datadir.rst.txt new file mode 100644 index 000000000..bfec66d41 --- /dev/null +++ b/3.7.0/_sources/api/datadir.rst.txt @@ -0,0 +1,27 @@ +.. _data_directory: + +Data Directory +=============== + +pyproj.datadir.get_data_dir +--------------------------- + +.. autofunction:: pyproj.datadir.get_data_dir + + +pyproj.datadir.set_data_dir +--------------------------- + +.. autofunction:: pyproj.datadir.set_data_dir + + +pyproj.datadir.append_data_dir +------------------------------ + +.. autofunction:: pyproj.datadir.append_data_dir + + +pyproj.datadir.get_user_data_dir +--------------------------------- + +.. autofunction:: pyproj.datadir.get_user_data_dir diff --git a/3.7.0/_sources/api/enums.rst.txt b/3.7.0/_sources/api/enums.rst.txt new file mode 100644 index 000000000..1af37cda2 --- /dev/null +++ b/3.7.0/_sources/api/enums.rst.txt @@ -0,0 +1,20 @@ +Enumerations +============ + +.. autoclass:: pyproj.enums.WktVersion + :members: + + +.. autoclass:: pyproj.enums.ProjVersion + :members: + + +.. autoclass:: pyproj.enums.TransformDirection + :members: + + +.. autoclass:: pyproj.enums.PJType + :members: + +.. autoclass:: pyproj.enums.GeodIntermediateFlag + :members: diff --git a/3.7.0/_sources/api/exceptions.rst.txt b/3.7.0/_sources/api/exceptions.rst.txt new file mode 100644 index 000000000..4ca936899 --- /dev/null +++ b/3.7.0/_sources/api/exceptions.rst.txt @@ -0,0 +1,5 @@ +Exceptions +========== + +.. automodule:: pyproj.exceptions + :members: diff --git a/3.7.0/_sources/api/geod.rst.txt b/3.7.0/_sources/api/geod.rst.txt new file mode 100644 index 000000000..472ac65ac --- /dev/null +++ b/3.7.0/_sources/api/geod.rst.txt @@ -0,0 +1,14 @@ +Geod +==== + +pyproj.Geod +----------- + +.. autoclass:: pyproj.Geod + :members: + :show-inheritance: + :inherited-members: + :special-members: __init__ + +.. autoclass:: pyproj.geod.GeodIntermediateReturn + :members: diff --git a/3.7.0/_sources/api/global_context.rst.txt b/3.7.0/_sources/api/global_context.rst.txt new file mode 100644 index 000000000..c58b214fe --- /dev/null +++ b/3.7.0/_sources/api/global_context.rst.txt @@ -0,0 +1,25 @@ +.. _global_context: + +Global Context +============== + +.. deprecated:: 3.7.0 No longer necessary as there is only one context per thread now. + +If you have a single-threaded application that generates many objects, +enabling the use of the global context can provide performance enhancements. + +.. warning:: The global context is not thread safe. +.. warning:: The global context maintains a connection to the database + through the duration of each python session and is closed + once the program terminates. + +How to enable: + +- Using :func:`pyproj.set_use_global_context`. +- Using the environment variable `PYPROJ_GLOBAL_CONTEXT`. + + +pyproj.set_use_global_context +----------------------------- + +.. autofunction:: pyproj.set_use_global_context diff --git a/3.7.0/_sources/api/index.rst.txt b/3.7.0/_sources/api/index.rst.txt new file mode 100644 index 000000000..a1711b23d --- /dev/null +++ b/3.7.0/_sources/api/index.rst.txt @@ -0,0 +1,21 @@ +API Documentation +================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + crs/index + transformer + geod + proj + database + list + datadir + network + sync + global_context + enums + aoi + exceptions + show_versions diff --git a/3.7.0/_sources/api/list.rst.txt b/3.7.0/_sources/api/list.rst.txt new file mode 100644 index 000000000..e17df16cb --- /dev/null +++ b/3.7.0/_sources/api/list.rst.txt @@ -0,0 +1,26 @@ +Lists +===== + + +pyproj.list.get_proj_operations_map +----------------------------------- + +.. note:: The backwards compatible import is `pyproj.get_proj_operations_map` + +.. autofunction:: pyproj.list.get_proj_operations_map + + +pyproj.list.get_ellps_map +-------------------------- + +.. note:: The backwards compatible import is `pyproj.get_ellps_map` + +.. autofunction:: pyproj.list.get_ellps_map + + +pyproj.list.get_prime_meridians_map +------------------------------------ + +.. note:: The backwards compatible import is `pyproj.get_prime_meridians_map` + +.. autofunction:: pyproj.list.get_prime_meridians_map diff --git a/3.7.0/_sources/api/network.rst.txt b/3.7.0/_sources/api/network.rst.txt new file mode 100644 index 000000000..9d56bc61c --- /dev/null +++ b/3.7.0/_sources/api/network.rst.txt @@ -0,0 +1,22 @@ +.. _network_api: + +PROJ Network Settings +====================== + + +pyproj.network.set_network_enabled +----------------------------------- + +.. autofunction:: pyproj.network.set_network_enabled + + +pyproj.network.is_network_enabled +---------------------------------- + +.. autofunction:: pyproj.network.is_network_enabled + + +pyproj.network.set_ca_bundle_path +---------------------------------- + +.. autofunction:: pyproj.network.set_ca_bundle_path diff --git a/3.7.0/_sources/api/proj.rst.txt b/3.7.0/_sources/api/proj.rst.txt new file mode 100644 index 000000000..d82027dbb --- /dev/null +++ b/3.7.0/_sources/api/proj.rst.txt @@ -0,0 +1,27 @@ +Proj +==== + + +`pyproj.Proj` is functionally equivalent to the `proj` command line tool in PROJ. + +The PROJ docs say:: + + The `proj` program is limited to converting between geographic and + projection coordinates within one datum. + + +pyproj.Proj +----------- + +.. autoclass:: pyproj.Proj + :members: + :inherited-members: + :special-members: __init__, __call__ + :show-inheritance: + + +pyproj.proj.Factors +------------------- + +.. autoclass:: pyproj.proj.Factors + :members: diff --git a/3.7.0/_sources/api/show_versions.rst.txt b/3.7.0/_sources/api/show_versions.rst.txt new file mode 100644 index 000000000..22ddd88c6 --- /dev/null +++ b/3.7.0/_sources/api/show_versions.rst.txt @@ -0,0 +1,7 @@ +Show Versions +============= + +pyproj.show_versions +-------------------- + +.. autofunction:: pyproj.show_versions diff --git a/3.7.0/_sources/api/sync.rst.txt b/3.7.0/_sources/api/sync.rst.txt new file mode 100644 index 000000000..f7d7e4498 --- /dev/null +++ b/3.7.0/_sources/api/sync.rst.txt @@ -0,0 +1,13 @@ +Sync Transformation Grids +========================= + +pyproj.sync.get_transform_grid_list +------------------------------------ + +.. autofunction:: pyproj.sync.get_transform_grid_list + + +pyproj.sync.get_proj_endpoint +------------------------------ + +.. autofunction:: pyproj.sync.get_proj_endpoint diff --git a/3.7.0/_sources/api/transformer.rst.txt b/3.7.0/_sources/api/transformer.rst.txt new file mode 100644 index 000000000..0d3fa2f51 --- /dev/null +++ b/3.7.0/_sources/api/transformer.rst.txt @@ -0,0 +1,47 @@ +.. _transformer: + +Transformer +=========== + + +The `pyproj.Transformer` has the capabilities of performing 2D, 3D, and 4D (time) +transformations. It can do anything that the PROJ command line programs +:ref:`proj`, :ref:`cs2cs`, and :ref:`cct` can do. +This means that it allows translation between any pair of definable coordinate systems, +including support for datum transformation. + + +.. warning:: The axis order may be swapped if the source and destination + CRS's are defined as having the first coordinate component point in a + northerly direction (See PROJ FAQ on + `axis order `_). + You can check the axis order with the :class:`pyproj.crs.CRS` class. If you prefer to + keep your axis order as always x,y, you can use the `always_xy` option when + creating the :class:`pyproj.transformer.Transformer`. + + +pyproj.Transformer +------------------ + +.. autoclass:: pyproj.transformer.Transformer + :members: + + +pyproj.transformer.TransformerGroup +----------------------------------- + +.. autoclass:: pyproj.transformer.TransformerGroup + :members: + :special-members: __init__ + + +pyproj.transform +---------------- + +.. autofunction:: pyproj.transformer.transform + + +pyproj.itransform +----------------- + +.. autofunction:: pyproj.transformer.itransform diff --git a/3.7.0/_sources/build_crs.rst.txt b/3.7.0/_sources/build_crs.rst.txt new file mode 100644 index 000000000..abf26f036 --- /dev/null +++ b/3.7.0/_sources/build_crs.rst.txt @@ -0,0 +1,181 @@ +Building a Coordinate Reference System +====================================== + +.. versionadded:: 2.5.0 + +PROJ strings have the potential to lose much of the information +about a coordinate reference system (CRS). + +More information: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems + +However, PROJ strings make it really simple to construct a CRS. +This addition is meant to simplify the process of transitioning +from the PROJ form of the string to the WKT form WKT. The CRS +classes can be used in the :meth:`pyproj.transformer.Transformer.from_crs` +method just like the :class:`pyproj.crs.CRS` class. + +The current set of classes does not cover every possible use case, +but hopefully it is enough to get you started. +If you notice something is missing that you need, feel free to open an issue on GitHub. + + +Here are links to the API docs for the pieces you need to get started: + +- :ref:`crs` +- :ref:`coordinate_operation` +- :ref:`datum` +- :ref:`coordinate_system` + + +Geographic CRS +-------------- + +This is a simple example of creating a lonlat projection. + +PROJ string:: + + +proj=longlat +datum=WGS84 +no_defs + +.. code-block:: python + + from pyproj.crs import GeographicCRS + + geog_crs = GeographicCRS() + geog_wkt = geog_crs.to_wkt() + + +This example is meant to show off different initialization methods. +It can be simplified to not use the Ellipsoid or PrimeMeridian objects. + +PROJ string:: + + +proj=longlat +ellps=airy +pm=lisbon +no_defs + +.. code-block:: python + + from pyproj.crs import Ellipsoid, GeographicCRS, PrimeMeridian + from pyproj.crs.datum import CustomDatum + + cd = CustomDatum( + ellipsoid=Ellipsoid.from_epsg(7001), + prime_meridian=PrimeMeridian.from_name("Lisbon"), + ) + geog_crs = GeographicCRS(datum=cd) + geog_wkt = geog_crs.to_wkt() + + +Projected CRS +------------- + +Simple example using defaults. + +PROJ string:: + + +proj=aea +lat_0=0 +lon_0=0 +lat_1=0 +lat_2=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs + +.. code-block:: python + + from pyproj.crs import ProjectedCRS + from pyproj.crs.coordinate_operation import AlbersEqualAreaConversion + + aeaop = AlbersEqualAreaConversion(0, 0) + proj_crs = ProjectedCRS(conversion=aeaop) + crs_wkt = proj_crs.to_wkt() + + +More complex example with custom parameters. + +PROJ string:: + + +proj=utm +zone=14 +a=6378137 +b=6356752 +pm=lisbon +units=m +no_defs + +.. code-block:: python + + from pyproj.crs import GeographicCRS, ProjectedCRS + from pyproj.crs.coordinate_operation import UTMConversion + from pyproj.crs.datum import CustomDatum, CustomEllipsoid + + ell = CustomEllipsoid(semi_major_axis=6378137, semi_minor_axis=6356752) + cd = CustomDatum(ellipsoid=ell, prime_meridian="Lisbon") + proj_crs = ProjectedCRS( + conversion=UTMConversion(14), geodetic_crs=GeographicCRS(datum=cd) + ) + crs_wkt = proj_crs.to_wkt() + + +Bound CRS +--------- + +This is an example building a CRS with `towgs84`. + +PROJ string:: + + +proj=tmerc +lat_0=0 +lon_0=15 +k=0.9996 +x_0=2520000 +y_0=0 +ellps=intl +towgs84=-122.74,-34.27,-22.83,-1.884,-3.4,-3.03,-15.62 +units=m +no_defs + +.. code-block:: python + + from pyproj.crs import BoundCRS, Ellipsoid, GeographicCRS, ProjectedCRS + from pyproj.crs.coordinate_operation import ( + TransverseMercatorConversion, + ToWGS84Transformation, + ) + from pyproj.crs.datum import CustomDatum + import pyproj + + proj_crs = ProjectedCRS( + conversion=TransverseMercatorConversion( + latitude_natural_origin=0, + longitude_natural_origin=15, + false_easting=2520000, + false_northing=0, + scale_factor_natural_origin=0.9996, + ), + geodetic_crs=GeographicCRS( + datum=CustomDatum(ellipsoid="International 1924 (Hayford 1909, 1910)") + ), + ) + bound_crs = BoundCRS( + source_crs=proj_crs, + target_crs="WGS 84", + transformation=ToWGS84Transformation( + proj_crs.geodetic_crs, -122.74, -34.27, -22.83, -1.884, -3.4, -3.03, -15.62 + ), + ) + crs_wkt = bound_crs.to_wkt() + + +Compound CRS +------------- + +The PROJ string is quite lossy in this example, so it is not provided. + +.. code-block:: python + + from pyproj.crs import CompoundCRS, GeographicCRS, ProjectedCRS, VerticalCRS + from pyproj.crs.coordinate_system import Cartesian2DCS, VerticalCS + from pyproj.crs.coordinate_operation import LambertConformalConic2SPConversion + + + vertcrs = VerticalCRS( + name="NAVD88 height", + datum="North American Vertical Datum 1988", + vertical_cs=VerticalCS(), + geoid_model="GEOID12B", + ) + projcrs = ProjectedCRS( + name="NAD83 / Pennsylvania South", + conversion=LambertConformalConic2SPConversion( + latitude_false_origin=39.3333333333333, + longitude_false_origin=-77.75, + latitude_first_parallel=40.9666666666667, + latitude_second_parallel=39.9333333333333, + easting_false_origin=600000, + northing_false_origin=0, + ), + geodetic_crs=GeographicCRS(datum="North American Datum 1983"), + cartesian_cs=Cartesian2DCS(), + ) + compcrs = CompoundCRS( + name="NAD83 / Pennsylvania South + NAVD88 height", components=[projcrs, vertcrs] + ) + crs_wkt = compcrs.to_wkt() diff --git a/3.7.0/_sources/build_crs_cf.rst.txt b/3.7.0/_sources/build_crs_cf.rst.txt new file mode 100644 index 000000000..f82c4b062 --- /dev/null +++ b/3.7.0/_sources/build_crs_cf.rst.txt @@ -0,0 +1,195 @@ +.. _build_crs_cf: + +Managing CRS to and from CF +============================ + +http://cfconventions.org/cf-conventions/cf-conventions.html + +Exporting CRS to CF +-------------------- +When exporting a CRS to the Climate and Forecast (CF) conventions, +you need both the grid mapping as well as the coordinate system. +If you don't use the coordinate system, then you will lose the units +of your projection. + + +In this example, this is the CRS we will use: + +.. code-block:: python + + from pyproj import CRS + + crs = CRS("EPSG:4326") + + +To get the grid mapping you use :meth:`pyproj.crs.CRS.to_cf`: + +.. versionadded:: 2.2.0 + +.. code-block:: python + + cf_grid_mapping = crs.to_cf() + + +Contents of `cf_grid_mapping`:: + + + {'crs_wkt': 'GEOGCRS["WGS 84",DATUM["World Geodetic System ' + ....,ID["EPSG",4326]]', + 'geographic_crs_name': 'WGS 84', + 'grid_mapping_name': 'latitude_longitude', + 'inverse_flattening': 298.257223563, + 'longitude_of_prime_meridian': 0.0, + 'prime_meridian_name': 'Greenwich', + 'reference_ellipsoid_name': 'WGS 84', + 'semi_major_axis': 6378137.0, + 'semi_minor_axis': 6356752.314245179} + + +To get the coordinate system, you use :meth:`pyproj.crs.CRS.cs_to_cf`: + +.. versionadded:: 3.0.0 + +.. code-block:: python + + cf_coordinate_system = crs.cs_to_cf() + + +Contents of `cf_coordinate_system`:: + + [{'long_name': 'geodetic latitude coordinate', + 'standard_name': 'latitude', + 'units': 'degrees_north', + 'axis': 'Y'}, + {'long_name': 'geodetic longitude coordinate', + 'standard_name': 'longitude', + 'units': 'degrees_east', + 'axis': 'X'}] + + +Importing CRS from CF +---------------------- + +When importing a CRS from the Climate and Forecast (CF) conventions, +you need both the grid mapping as well as the coordinate system. +If you don't use the coordinate system, then you will lose the units +of your projection. + +.. note:: If the CF `crs_wkt` attribute is available, the coordinate system is + inside of the WKT and can be used to create the CRS in a single step. + +.. warning:: If building from grid mapping, be mindful of the axis order. https://github.com/cf-convention/cf-conventions/pull/224 + + +Build the CRS from CF grid mapping: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this example, this is the grid mapping and coordinate system we will use:: + + variables: + double x(x) ; + x:standard_name = "projection_x_coordinate" ; + x:long_name = "Easting" ; + x:units = "m" ; + double y(y) ; + y:standard_name = "projection_y_coordinate" ; + y:long_name = "Northing" ; + y:units = "m" ; + int crsOSGB ; + crsOSGB:grid_mapping_name = "transverse_mercator"; + crsOSGB:semi_major_axis = 6377563.396 ; + crsOSGB:inverse_flattening = 299.3249646 ; + crsOSGB:longitude_of_prime_meridian = 0.0 ; + crsOSGB:latitude_of_projection_origin = 49.0 ; + crsOSGB:longitude_of_central_meridian = -2.0 ; + crsOSGB:scale_factor_at_central_meridian = 0.9996012717 ; + crsOSGB:false_easting = 400000.0 ; + crsOSGB:false_northing = -100000.0 ; + +.. note:: If the units are meters as in this example, + then no further changes are necessary. + +.. code-block:: python + + from pyproj import CRS + + crs = CRS.from_cf( + { + "grid_mapping_name": "transverse_mercator", + "semi_major_axis": 6377563.396, + "inverse_flattening": 299.3249646, + "longitude_of_prime_meridian": 0.0, + "latitude_of_projection_origin": 49.0, + "longitude_of_central_meridian": -2.0, + "scale_factor_at_central_meridian": 0.9996012717, + "false_easting": 400000.0, + "false_northing": -100000.0, + } + ) + + +Modify the CRS with coordinate system: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 3.0.0 + +.. note:: If the CF `crs_wkt` attribute is available, the coordinate system is + inside of the WKT and can be used to create the CRS in a single step. + +.. warning:: Be mindful of the axis order. https://github.com/cf-convention/cf-conventions/pull/224 + + +In this example, assume everything is the same as above. +However, the units are instead `US_Survey_Foot`:: + + variables: + double x(x) ; + x:standard_name = "projection_x_coordinate" ; + x:long_name = "Easting" ; + x:units = "US_Survey_Foot" ; + double y(y) ; + y:standard_name = "projection_y_coordinate" ; + y:long_name = "Northing" ; + y:units = "US_Survey_Foot" ; + ... + + +In this case, you will need to get the unit conversion factor: + +https://github.com/SciTools/cf-units + + +.. code-block:: python + + from cf_units import Unit + from pyproj import CRS + + cf_unit = Unit("US_Survey_Foot") + unit = { + "type": "LinearUnit", + "name": "US Survey Foot", + "conversion_factor": cf_unit.convert(1, "m"), + } + cartesian_cs = { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "CoordinateSystem", + "subtype": "Cartesian", + "axis": [ + {"name": "Easting", "abbreviation": "E", "direction": "east", "unit": unit}, + {"name": "Northing", "abbreviation": "N", "direction": "north", "unit": unit}, + ], + } + crs = CRS.from_cf( + { + "grid_mapping_name": "transverse_mercator", + "semi_major_axis": 6377563.396, + "inverse_flattening": 299.3249646, + "longitude_of_prime_meridian": 0.0, + "latitude_of_projection_origin": 49.0, + "longitude_of_central_meridian": -2.0, + "scale_factor_at_central_meridian": 0.9996012717, + "false_easting": 400000.0, + "false_northing": -100000.0, + }, + cartesian_cs=cartesian_cs, + ) diff --git a/3.7.0/_sources/cli.rst.txt b/3.7.0/_sources/cli.rst.txt new file mode 100644 index 000000000..e2f230620 --- /dev/null +++ b/3.7.0/_sources/cli.rst.txt @@ -0,0 +1,6 @@ +CLI +==== + +.. argparse:: + :ref: pyproj.__main__.parser + :prog: pyproj diff --git a/3.7.0/_sources/crs_compatibility.rst.txt b/3.7.0/_sources/crs_compatibility.rst.txt new file mode 100644 index 000000000..74610297a --- /dev/null +++ b/3.7.0/_sources/crs_compatibility.rst.txt @@ -0,0 +1,279 @@ +CRS Compatibility Guide for Geospatial Python +============================================== + +This is meant to be a guide to help you along the way of you use :class:`pyproj.crs.CRS` +with other Python Geospatial libraries. + +.. note:: WKT2 is the best format for storing your CRS according to the + `PROJ FAQ `__. + + +osgeo/gdal +---------- + +https://github.com/osgeo/gdal + +Converting from `osgeo.osr.SpatialReference` to `pyproj.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + from osgeo.osr import SpatialReference + from pyproj.crs import CRS + + osr_crs = SpatialReference() + osr_crs.ImportFromEPSG(4326) + if osgeo.version_info.major < 3: + proj_crs = CRS.from_wkt(osr_crs.ExportToWkt()) + else: + proj_crs = CRS.from_wkt(osr_crs.ExportToWkt(["FORMAT=WKT2_2018"])) + + +Converting from `pyproj.crs.CRS` to `osgeo.osr.SpatialReference` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: WKT2 is only supported in GDAL 3+ + +.. code-block:: python + + import osgeo + from osgeo.osr import SpatialReference + from pyproj.crs import CRS + from pyproj.enums import WktVersion + + proj_crs = CRS.from_epsg(4326) + + osr_crs = SpatialReference() + if osgeo.version_info.major < 3: + osr_crs.ImportFromWkt(proj_crs.to_wkt(WktVersion.WKT1_GDAL)) + else: + osr_crs.ImportFromWkt(proj_crs.to_wkt()) + + +rasterio +-------- + +https://github.com/mapbox/rasterio + +Converting from `rasterio.crs.CRS` to `pyproj.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you have `rasterio >= 1.0.14`, then you can pass in the `rasterio.crs.CRS` +directly:: + + import rasterio + import rasterio.crs + from pyproj.crs import CRS + + with rasterio.Env(OSR_WKT_FORMAT="WKT2_2018"): + rio_crs = rasterio.crs.CRS.from_epsg(4326) + proj_crs = CRS.from_user_input(rio_crs) + +Otherwise, you should use the `wkt` property:: + + import rasterio.crs + from pyproj.crs import CRS + + with rasterio.Env(OSR_WKT_FORMAT="WKT2_2018"): + rio_crs = rasterio.crs.CRS.from_epsg(4326) + proj_crs = CRS.from_wkt(rio_crs.wkt) + +Converting from `pyproj.crs.CRS` to `rasterio.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: WKT2 is only supported in GDAL 3+ + +If you have rasterio >= 1.0.26 and GDAL 3+, then you can pass in the `pyproj.crs.CRS` +directly:: + + import rasterio.crs + from pyproj.crs import CRS + + proj_crs = CRS.from_epsg(4326) + rio_crs = rasterio.crs.CRS.from_user_input(proj_crs) + +If you want to be compatible across GDAL/rasterio versions, you can do:: + + from packaging import version + + import rasterio + import rasterio.crs + from pyproj.crs import CRS + from pyproj.enums import WktVersion + + proj_crs = CRS.from_epsg(4326) + if version.parse(rasterio.__gdal_version__) < version.parse("3.0.0") + rio_crs = rasterio.crs.CRS.from_wkt(proj_crs.to_wkt(WktVersion.WKT1_GDAL)) + else: + rio_crs = rasterio.crs.CRS.from_wkt(proj_crs.to_wkt()) + +fiona +------ + +https://github.com/Toblerity/Fiona + +Converting from `fiona` CRS to `pyproj.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Fiona currently stores the CRS as a PROJ string dictionary in the `crs` +attribute. As such, it is best to use the `crs_wkt` attribute. + +It is also useful to know that plans exist to add CRS class. +Related GitHub issue `here `__. + + +Example:: + + import fiona + from pyproj.crs import CRS + + with fiona.Env(OSR_WKT_FORMAT="WKT2_2018"), fiona.open(...) as fds: + proj_crs = CRS.from_wkt(fds.crs_wkt) + + +Converting from `pyproj.crs.CRS` for `fiona` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: WKT2 is only supported in GDAL 3+ + +If you want to be compatible across GDAL versions, you can do:: + + from packaging import version + + import fiona + from pyproj.crs import CRS + + proj_crs = CRS.from_epsg(4326) + + if version.parse(fiona.__gdal_version__) < version.parse("3.0.0"): + fio_crs = proj_crs.to_wkt(WktVersion.WKT1_GDAL) + else: + # GDAL 3+ can use WKT2 + fio_crs = dc_crs.to_wkt() + + # with fiona.open(..., "w", crs_wkt=fio_crs) as fds: + # ... + + +geopandas +--------- + +https://github.com/geopandas/geopandas + +Also see the `geopandas guide for upgrading to use pyproj CRS class `__ + +Preparing `pyproj.crs.CRS` for `geopandas` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + import fiona + import geopandas + from pyproj.crs import CRS + from pyproj.enums import WktVersion + + proj_crs = CRS.from_epsg(4326) + + if version.parse(geopandas.__version__) >= version.parse("0.7.0"): + # geopandas uses pyproj.crs.CRS + geo_crs = proj_crs + elif version.parse(geopandas.__version__) >= version.parse("0.6.0"): + # this version of geopandas uses always_xy=True so WKT version is safe + if version.parse(fiona.__gdal_version__) < version.parse("3.0.0"): + geo_crs = proj_crs.to_wkt(WktVersion.WKT1_GDAL) + else: + # GDAL 3+ can use WKT2 + geo_crs = dc_crs.to_wkt() + else: + geo_crs = dc_crs.to_proj4() + + +`geopandas` to `pyproj.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:meth:`pyproj.crs.CRS.from_user_input` can handle anything across the `geopandas` +versions. The only gotcha would be if it is `None`. + + +.. code-block:: python + + import geopandas + from pyproj.crs import CRS + + gdf = geopandas.read_file(...) + proj_crs = CRS.from_user_input(gdf.crs) + + +cartopy +------- + +https://github.com/SciTools/cartopy + +.. note:: These examples require cartopy 0.20+ + +Preparing `pyproj.crs.CRS` for `cartopy.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: This only works for CRS created with WKT2, + PROJ JSON, or a spatial reference ID (i.e. EPSG) + with the area of use defined. Otherwise, + the x_limits and y_limits will not work. + +.. code-block:: python + + import cartopy.crs as ccrs + from pyproj.crs import CRS + + # geographic + proj_crs = CRS.from_epsg(4326) + cart_crs = ccrs.CRS(proj_crs) + + # projected + proj_crs = CRS.from_epsg(6933) + cart_crs = ccrs.Projection(proj_crs) + + +Preparing `cartopy.crs.CRS` for `pyproj.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: `cartopy.crs.CRS` inherits from `pyproj.crs.CRS`, + so it should behave like a `pyproj.crs.CRS`. + +.. code-block:: python + + + from cartopy.crs import PlateCarree + from pyproj.crs import CRS + + cart_crs = PlateCarree() + proj_crs = CRS.from_user_input(cart_crs) + + +pycrs +----- + +https://github.com/karimbahgat/PyCRS + +.. warning:: Currently does not support WKT2 + +Preparing `pyproj.crs.CRS` for `pycrs` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + import pycrs + from pyproj.crs import CRS + + proj_crs = CRS.from_epsg(4326) + py_crs = pycrs.parse.from_ogc_wkt(proj_crs.to_wkt("WKT1_GDAL")) + + +Preparing `pycrs` for `pyproj.crs.CRS` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code-block:: python + + + import pycrs + from pyproj.crs import CRS + + py_crs = pycrs.parse.from_epsg_code(4326) + proj_crs = CRS.from_wkt(py_crs.to_ogc_wkt()) diff --git a/3.7.0/_sources/examples.rst.txt b/3.7.0/_sources/examples.rst.txt new file mode 100644 index 000000000..6b063f365 --- /dev/null +++ b/3.7.0/_sources/examples.rst.txt @@ -0,0 +1,478 @@ +.. _examples: + +Getting Started +=============== + +There are examples of usage within the API documentation and tests. This +section is to demonstrate recommended usage. + +Also see: :ref:`gotchas` + + +Using CRS +--------- +For more usage examples and documentation see :class:`pyproj.crs.CRS`. + +Initializing CRS +~~~~~~~~~~~~~~~~ + +The :class:`pyproj.crs.CRS` class can be initialized in many different ways. +Here are some examples of initialization. + + +.. code:: python + + >>> from pyproj import CRS + >>> crs = CRS.from_epsg(4326) + >>> crs = CRS.from_string("EPSG:4326") + >>> crs = CRS.from_proj4("+proj=latlon") + >>> crs = CRS.from_user_input(4326) + + +Converting CRS to a different format +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. warning:: You will likely lose important projection + information when converting to a PROJ string from + another format. See: https://proj4.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems + + +.. code:: python + + >>> from pyproj import CRS + >>> crs = CRS.from_epsg(4326) + >>> crs.to_epsg() + 4326 + >>> crs.to_authority() + ('EPSG', '4326') + >>> crs = CRS.from_proj4("+proj=omerc +lat_0=-36 +lonc=147 +alpha=-54 +k=1 +x_0=0 +y_0=0 +gamma=0 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0") + >>> crs + + Name: unknown + Axis Info [cartesian]: + - E[east]: Easting (metre) + - N[north]: Northing (metre) + Area of Use: + - undefined + Coordinate Operation: + - name: Transformation from unknown to WGS84 + - method: Position Vector transformation (geog2D domain) + Datum: Unknown based on WGS84 ellipsoid + - Ellipsoid: WGS 84 + - Prime Meridian: Greenwich + Source CRS: unknown + + >>> print(crs.to_wkt(pretty=True)) + BOUNDCRS[ + SOURCECRS[ + PROJCRS["unknown", + BASEGEOGCRS["unknown", + DATUM["Unknown based on WGS84 ellipsoid", + ELLIPSOID["WGS 84",6378137,298.257223563, + LENGTHUNIT["metre",1], + ID["EPSG",7030]]], + ... + PARAMETER["Z-axis rotation",0, + ID["EPSG",8610]], + PARAMETER["Scale difference",1, + ID["EPSG",8611]]]] + + >>> from pyproj.enums import WktVersion + >>> print(crs.to_wkt(WktVersion.WKT1_GDAL, pretty=True)) + PROJCS["unknown", + GEOGCS["unknown", + DATUM["Unknown_based_on_WGS84_ellipsoid", + SPHEROID["WGS 84",6378137,298.257223563, + AUTHORITY["EPSG","7030"]], + TOWGS84[0,0,0,0,0,0,0]], + PRIMEM["Greenwich",0, + AUTHORITY["EPSG","8901"]], + UNIT["degree",0.0174532925199433, + AUTHORITY["EPSG","9122"]]], + PROJECTION["Hotine_Oblique_Mercator_Azimuth_Center"], + PARAMETER["latitude_of_center",-36], + PARAMETER["longitude_of_center",147], + PARAMETER["azimuth",-54], + PARAMETER["rectified_grid_angle",0], + PARAMETER["scale_factor",1], + PARAMETER["false_easting",0], + PARAMETER["false_northing",0], + UNIT["metre",1, + AUTHORITY["EPSG","9001"]], + AXIS["Easting",EAST], + AXIS["Northing",NORTH]] + + >>> from pprint import pprint + >>> pprint(crs.to_cf()) + {'azimuth_of_central_line': -54, + 'crs_wkt': 'BOUNDCRS[SOURCECRS[PROJCRS["unknown",BASEGEOGCRS["unknown",DATUM["Unknown ' + ... + 'difference",1,ID["EPSG",8611]]]]', + 'false_easting': 0.0, + 'false_northing': 0.0, + 'grid_mapping_name': 'oblique_mercator', + 'horizontal_datum_name': 'Unknown based on WGS84 ellipsoid', + 'inverse_flattening': 298.257223563, + 'latitude_of_projection_origin': -36.0, + 'longitude_of_prime_meridian': 0.0, + 'longitude_of_projection_origin': 147.0, + 'prime_meridian_name': 'Greenwich', + 'reference_ellipsoid_name': 'WGS 84', + 'scale_factor_at_projection_origin': 1.0, + 'semi_major_axis': 6378137.0, + 'semi_minor_axis': 6356752.314245179, + 'towgs84': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]} + + +Extracting attributes from CRS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are many attributes you can pull from the :class:`pyproj.crs.CRS`. +This is just a small subset of what is available. + + +.. code:: python + + >>> crs = CRS("urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717") + >>> crs + + Name: KKJ / Finland Uniform Coordinate System + N60 height + Axis Info [cartesian|vertical]: + - X[north]: Northing (metre) + - Y[east]: Easting (metre) + - H[up]: Gravity-related height (metre) + Area of Use: + - undefined + Datum: Kartastokoordinaattijarjestelma (1966) + - Ellipsoid: International 1924 + - Prime Meridian: Greenwich + Sub CRS: + - KKJ / Finland Uniform Coordinate System + - N60 height + >>> crs.sub_crs_list + [ + Name: KKJ / Finland Uniform Coordinate System + Axis Info [cartesian]: + - X[north]: Northing (metre) + - Y[east]: Easting (metre) + Area of Use: + - name: Finland - 25.5°E to 28.5°E onshore. Also all country. + - bounds: (19.24, 59.75, 31.59, 70.09) + Coordinate Operation: + - name: Finland Uniform Coordinate System + - method: Transverse Mercator + Datum: Kartastokoordinaattijarjestelma (1966) + - Ellipsoid: International 1924 + - Prime Meridian: Greenwich + , + Name: N60 height + Axis Info [vertical]: + - H[up]: Gravity-related height (metre) + Area of Use: + - name: Finland - onshore. + - bounds: (19.24, 59.75, 31.59, 70.09) + Datum: Helsinki 1960 + - Ellipsoid: undefined + - Prime Meridian: undefined + ] + >>> cop = crs.sub_crs_list[0].coordinate_operation + >>> print(cop.to_wkt(pretty=True)) + CONVERSION["Finland Uniform Coordinate System", + METHOD["Transverse Mercator", + ID["EPSG",9807]], + PARAMETER["Latitude of natural origin",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8801]], + PARAMETER["Longitude of natural origin",27, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8802]], + PARAMETER["Scale factor at natural origin",1, + SCALEUNIT["unity",1], + ID["EPSG",8805]], + PARAMETER["False easting",3500000, + LENGTHUNIT["metre",1], + ID["EPSG",8806]], + PARAMETER["False northing",0, + LENGTHUNIT["metre",1], + ID["EPSG",8807]]] + >>> cop.method_code + '9807' + >>> cop.method_name + 'Transverse Mercator' + >>> cop.params + [Param(name=Latitude of natural origin, auth_name=EPSG, code=8801, value=0.0, unit_name=degree, unit_auth_name=, unit_code=, unit_category=angular), + ... + Param(name=False northing, auth_name=EPSG, code=8807, value=0.0, unit_name=metre, unit_auth_name=, unit_code=, unit_category=linear)] + + +Find UTM CRS by Latitude and Longitude +--------------------------------------- + +.. note:: For more database methods see: :ref:`database`. + +.. code-block:: python + + from pyproj import CRS + from pyproj.aoi import AreaOfInterest + from pyproj.database import query_utm_crs_info + + utm_crs_list = query_utm_crs_info( + datum_name="WGS 84", + area_of_interest=AreaOfInterest( + west_lon_degree=-93.581543, + south_lat_degree=42.032974, + east_lon_degree=-93.581543, + north_lat_degree=42.032974, + ), + ) + utm_crs = CRS.from_epsg(utm_crs_list[0].code) + + +Transformations from CRS to CRS +------------------------------- + +Step 1: Inspect CRS definition to ensure proper area of use and axis order +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For more options available for inspection, usage examples, +and documentation see :class:`pyproj.crs.CRS`. + +.. code:: python + + >>> from pyproj import CRS + >>> crs_4326 = CRS.from_epsg(4326) + >>> crs_4326 + + Name: WGS 84 + Axis Info [ellipsoidal]: + - Lat[north]: Geodetic latitude (degree) + - Lon[east]: Geodetic longitude (degree) + Area of Use: + - name: World + - bounds: (-180.0, -90.0, 180.0, 90.0) + Datum: World Geodetic System 1984 + - Ellipsoid: WGS 84 + - Prime Meridian: Greenwich + + >>> crs_26917 = CRS.from_epsg(26917) + >>> crs_26917 + + Name: NAD83 / UTM zone 17N + Axis Info [cartesian]: + - E[east]: Easting (metre) + - N[north]: Northing (metre) + Area of Use: + - name: North America - 84°W to 78°W and NAD83 by country + - bounds: (-84.0, 23.81, -78.0, 84.0) + Coordinate Operation: + - name: UTM zone 17N + - method: Transverse Mercator + Datum: North American Datum 1983 + - Ellipsoid: GRS 1980 + - Prime Meridian: Greenwich + + +Note that `crs_4326` has the latitude (north) axis first and the `crs_26917` +has the easting axis first. This means that in the transformation, we will need +to input the data with latitude first and longitude second. Also, note that the +second projection is a UTM projection with bounds (-84.0, 23.81, -78.0, 84.0) which +are in the form (min_x, min_y, max_x, max_y), so the transformation input/output should +be within those bounds for best results. + + +Step 2: Create Transformer to convert from CRS to CRS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`pyproj.transformer.Transformer` can be initialized with anything supported +by :meth:`pyproj.crs.CRS.from_user_input`. There are a couple of examples added +here for demonstration. For more usage examples and documentation, +see :class:`pyproj.transformer.Transformer`. + + +.. code:: python + + >>> from pyproj import Transformer + >>> transformer = Transformer.from_crs(crs_4326, crs_26917) + >>> transformer = Transformer.from_crs(4326, 26917) + >>> transformer = Transformer.from_crs("EPSG:4326", "EPSG:26917") + >>> transformer + + Inverse of NAD83 to WGS 84 (1) + UTM zone 17N + >>> transformer.transform(50, -80) + (571666.4475041276, 5539109.815175673) + +If you prefer to always have the axis order in the x,y or lon,lat order, +you can use the `always_xy` option when creating the transformer. + +.. code:: python + + >>> from pyproj import Transformer + >>> transformer = Transformer.from_crs("EPSG:4326", "EPSG:26917", always_xy=True) + >>> transformer.transform(-80, 50) + (571666.4475041276, 5539109.815175673) + + + +Converting between geographic and projection coordinates within one datum +------------------------------------------------------------------------- + +Step 1: Retrieve the geodetic CRS based on original CRS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + >>> from pyproj import CRS + >>> crs = CRS.from_epsg(3857) + >>> crs + + Name: WGS 84 / Pseudo-Mercator + Axis Info [cartesian]: + - X[east]: Easting (metre) + - Y[north]: Northing (metre) + Area of Use: + - name: World - 85°S to 85°N + - bounds: (-180.0, -85.06, 180.0, 85.06) + Coordinate Operation: + - name: Popular Visualisation Pseudo-Mercator + - method: Popular Visualisation Pseudo Mercator + Datum: World Geodetic System 1984 + - Ellipsoid: WGS 84 + - Prime Meridian: Greenwich + + >>> crs.geodetic_crs + + Name: WGS 84 + Axis Info [ellipsoidal]: + - Lat[north]: Geodetic latitude (degree) + - Lon[east]: Geodetic longitude (degree) + Area of Use: + - name: World + - bounds: (-180.0, -90.0, 180.0, 90.0) + Datum: World Geodetic System 1984 + - Ellipsoid: WGS 84 + - Prime Meridian: Greenwich + + + +Step 2: Create Transformer to convert from geodetic CRS to CRS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + >>> proj = Transformer.from_crs(crs.geodetic_crs, crs) + >>> proj + + Popular Visualisation Pseudo-Mercator + Area of Use: + - name: World + - bounds: (-180.0, -90.0, 180.0, 90.0) + >>> proj.transform(12, 15) + (1669792.3618991035, 1345708.4084091093) + + +4D Transformations with Time +---------------------------- + +.. note:: If you are doing a transformation with a CRS that is time based, + it is recommended to include the time in the transformation operation. + + +.. code:: python + + >>> transformer = Transformer.from_crs(7789, 8401) + >>> transformer + + ITRF2014 to ETRF2014 (1) + >>> transformer.transform(xx=3496737.2679, yy=743254.4507, zz=5264462.9620, tt=2019.0) + (3496737.757717311, 743253.9940103051, 5264462.701132784, 2019.0) + + + +Geodesic calculations +--------------------- +This is useful if you need to calculate the distance between two +points or the area of a geometry on Earth's surface. + +For more examples of usage and documentation, see :class:`pyproj.Geod`. + + +Creating Geod class +~~~~~~~~~~~~~~~~~~~ + +This example demonstrates creating a :class:`pyproj.Geod` using an +ellipsoid name as well as deriving one using a :class:`pyproj.crs.CRS`. + +.. code:: python + + >>> from pyproj import CRS, Geod + >>> geod_clrk = Geod(ellps='clrk66') # Use Clarke 1866 ellipsoid. + >>> geod_clrk + Geod(ellps='clrk66') + >>> geod_wgs84 = CRS("EPSG:4326").get_geod() + >>> geod_wgs84 + Geod('+a=6378137 +f=0.0033528106647475126') + + +Geodesic line length +~~~~~~~~~~~~~~~~~~~~ + +Calculate the geodesic length of a line (See: :meth:`pyproj.Geod.line_length`): + +.. code:: python + + >>> from pyproj import Geod + >>> lats = [-72.9, -71.9, -74.9, -74.3, -77.5, -77.4, -71.7, -65.9, -65.7, + ... -66.6, -66.9, -69.8, -70.0, -71.0, -77.3, -77.9, -74.7] + >>> lons = [-74, -102, -102, -131, -163, 163, 172, 140, 113, + ... 88, 59, 25, -4, -14, -33, -46, -61] + >>> geod = Geod(ellps="WGS84") + >>> total_length = geod.line_length(lons, lats) + >>> f"{total_length:.3f}" + '14259605.611' + +Calculate the geodesic length of a shapely geometry (See: :meth:`pyproj.Geod.geometry_length`): + +.. code:: python + + >>> from pyproj import Geod + >>> from shapely.geometry import Point, LineString + >>> line_string = LineString([Point(1, 2), Point(3, 4)])) + >>> geod = Geod(ellps="WGS84") + >>> total_length = geod.geometry_length(line_string) + >>> f"{total_length:.3f}" + '313588.397' + + +Geodesic area +~~~~~~~~~~~~~ + +Calculate the geodesic area and perimeter of a polygon (See: :meth:`pyproj.Geod.polygon_area_perimeter`): + +.. code:: python + + >>> from pyproj import Geod + >>> geod = Geod('+a=6378137 +f=0.0033528106647475126') + >>> lats = [-72.9, -71.9, -74.9, -74.3, -77.5, -77.4, -71.7, -65.9, -65.7, + ... -66.6, -66.9, -69.8, -70.0, -71.0, -77.3, -77.9, -74.7] + >>> lons = [-74, -102, -102, -131, -163, 163, 172, 140, 113, + ... 88, 59, 25, -4, -14, -33, -46, -61] + >>> poly_area, poly_perimeter = geod.polygon_area_perimeter(lons, lats) + >>> f"{poly_area:.3f} {poly_perimeter:.3f}" + '13376856682207.406 14710425.407' + + +Calculate the geodesic area and perimeter of a shapely polygon (See: :meth:`pyproj.Geod.geometry_area_perimeter`): + + +.. code:: python + + >>> from pyproj import Geod + >>> from shapely.geometry import LineString, Point, Polygon + >>> geod = Geod('+a=6378137 +f=0.0033528106647475126') + >>> poly_area, poly_perimeter = geod.geometry_area_perimeter( + Polygon( + LineString([Point(1, 1), Point(1, 10), Point(10, 10), Point(10, 1)]), + holes=[LineString([Point(1, 2), Point(3, 4), Point(5, 2)])], + ) + ) + >>> f"{poly_area:.3f} {poly_perimeter:.3f}" + '-944373881400.339 3979008.036' diff --git a/3.7.0/_sources/gotchas.rst.txt b/3.7.0/_sources/gotchas.rst.txt new file mode 100644 index 000000000..9aee75f77 --- /dev/null +++ b/3.7.0/_sources/gotchas.rst.txt @@ -0,0 +1,293 @@ +.. _gotchas: + +Gotchas/FAQ +=========== + +This is a page for some suggestions, gotchas, and FAQs. + +Also see: + - :ref:`examples` + - :ref:`PROJ FAQ ` + + +What are the best formats to store the CRS information? +-------------------------------------------------------- + +In general, `Well-Known Text (WKT) `__ +or `Spatial Reference ID +(SRID) `__, such as EPSG +codes, are the preferred formats to describe a CRS. + +.. note:: WKT2 is preferred over WKT1. + +PROJ strings can be lossy for storing CRS information. +If you can avoid it, it is best to not use them. +Additionally, PROJ strings will likely not be supported +in future major version of PROJ for storing CRS information. + +More info: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems + + +Axis order changes in PROJ 6+ +----------------------------- +- https://proj.org/faq.html#why-is-the-axis-ordering-in-proj-not-consistent +- See warning at the top of :ref:`transformer` +- Examples of how to handle it: :ref:`examples` +- :ref:`min_confidence` + + +`+init=:` should be replaced with `:` +----------------------------------------------------------------------- + +The `+init=:` syntax is deprecated and will be removed +in future versions of PROJ. Also, if you use the `+init` syntax, +you may have problems initializing projections when the other syntax works. + +.. code-block:: python + + >>> from pyproj import CRS + >>> CRS("ESRI:54009") + + Name: World_Mollweide + Axis Info [cartesian]: + - E[east]: Easting (metre) + - N[north]: Northing (metre) + Area of Use: + - name: World + - bounds: (-180.0, -90.0, 180.0, 90.0) + Coordinate Operation: + - name: World_Mollweide + - method: Mollweide + Datum: World Geodetic System 1984 + - Ellipsoid: WGS 84 + - Prime Meridian: Greenwich + + >>> CRS("+init=ESRI:54009") + ... + pyproj.exceptions.CRSError: Invalid projection: +init=ESRI:54009 +type=crs: (Internal Proj Error: proj_create: cannot expand +init=ESRI:54009 +type=crs) + + +Proj (Not a generic latitude/longitude to projection converter) +--------------------------------------------------------------- + +:class:`pyproj.Proj` is limited to converting between geographic and +projection coordinates within one datum. If you have coordinates in latitude +and longitude, and you want to convert it to your projection, it is recommended +to use the :class:`pyproj.transformer.Transformer` as it takes into account datum +shifts. + +You likely want to start from `EPSG:4326` (WGS84) for coordinates as +latitude and longitude. + +.. code-block:: python + + >>> from pyproj import CRS + >>> crs_4326 = CRS("WGS84") + >>> crs_4326 + + Name: WGS 84 + Axis Info [ellipsoidal]: + - Lat[north]: Geodetic latitude (degree) + - Lon[east]: Geodetic longitude (degree) + Area of Use: + - name: World + - bounds: (-180.0, -90.0, 180.0, 90.0) + Datum: World Geodetic System 1984 + - Ellipsoid: WGS 84 + - Prime Meridian: Greenwich + +Then, use the :class:`pyproj.transformer.Transformer` to transform from latitude +and longitude to your projection as you might have a projection with a different +datum. + +.. code-block:: python + + >>> crs_proj = CRS("EPSG:28992") + >>> crs_proj + + Name: Amersfoort / RD New + Axis Info [cartesian]: + - X[east]: Easting (metre) + - Y[north]: Northing (metre) + Area of Use: + - name: Netherlands - onshore. + - bounds: (3.2, 50.75, 7.22, 53.7) + Coordinate Operation: + - name: RD New + - method: Oblique Stereographic + Datum: Amersfoort + - Ellipsoid: Bessel 1841 + - Prime Meridian: Greenwich + >>> crs_proj.datum == crs_4326.datum + False + >>> from pyproj import Transformer + >>> transformer = Transformer.from_crs(crs_4326, crs_proj) + >>> transformer.transform(52.067567, 5.068913) + (133175.3690698233, 453300.86739169655) + +If you use :class:`pyproj.Proj`, it will use the geodetic CRS with +from the projected CRS with the same datum to do the transformation, +which may not be what you want. + +.. code-block:: python + + >>> from pyproj import Proj + >>> Proj('epsg:28992')(5.068913, 52.067567) + (133148.22970574044, 453192.24450392975) + >>> transg = Transformer.from_crs(crs_proj.geodetic_crs, crs_proj) + >>> transg.transform(52.067567, 5.068913) + (133148.22970574044, 453192.24450392975) + + +.. _min_confidence: + +Why does the EPSG code return when using `EPSG:xxxx` and not with `+init=EPSG:xxxx`? +------------------------------------------------------------------------------------ + +From: https://gis.stackexchange.com/a/326919/144357 + + +The reason that the EPSG code does not appear with the CRS initialized with +the `init=` syntax is that the CRS are different. + +.. code-block:: python + + >>> from pyproj import CRS + >>> crs_deprecated = CRS(init="epsg:4544") + >>> crs = CRS("EPSG:4544") + >>> crs == crs_deprecated + False + +Upon further inspection of the `Axis Info` section, you can see that the difference +is in the **axis order**. + +.. code-block:: python + + >>> crs_deprecated + + Name: CGCS2000 / 3-degree Gauss-Kruger CM 105E + Axis Info [cartesian]: + - E[east]: Easting (metre) + - N[north]: Northing (metre) + Area of Use: + - name: China - 103.5°E to 106.5°E + - bounds: (103.5, 22.5, 106.5, 42.21) + Coordinate Operation: + - name: Gauss-Kruger CM 105E + - method: Transverse Mercator + Datum: China 2000 + - Ellipsoid: CGCS2000 + - Prime Meridian: Greenwich + + >>> crs + + Name: CGCS2000 / 3-degree Gauss-Kruger CM 105E + Axis Info [cartesian]: + - X[north]: Northing (metre) + - Y[east]: Easting (metre) + Area of Use: + - name: China - 103.5°E to 106.5°E + - bounds: (103.5, 22.5, 106.5, 42.21) + Coordinate Operation: + - name: Gauss-Kruger CM 105E + - method: Transverse Mercator + Datum: China 2000 + - Ellipsoid: CGCS2000 + - Prime Meridian: Greenwich + + +The reason the `min_confidence` parameter in +:meth:`pyproj.crs.CRS.to_epsg` and :meth:`pyproj.crs.CRS.to_authority` +exists is because you can initialize a CRS in several different methods and +some of them do not always correspond to an EPSG or authortiy code, but it +can be close enough. + +For example, if you have a WKT/PROJ string and you use it to create the CRS instance, +in most cases you want to be sure that the EPSG code given by to_epsg will give you a +CRS instance similar to the one created by the WKT/PROJ string. +However, if an EPSG code does not exist that matches you WKT/PROJ string with +a `min_confidence` you don't want to get that EPSG code back as it will make +you think that the WKT/PROJ string and the EPSG code are one and the same when +they are not. + +However, if you are only wanting to get the EPSG code that is closest +to the PROJ/WKT string, then you can reduce your min_confidence to a +threshold you are comfortable with. + +Here is an example of that: + +.. code-block:: python + + >>> crs_deprecated = CRS("+init=epsg:4326") + >>> crs_deprecated.to_epsg(100) + >>> crs_deprecated.to_epsg(70) + >>> crs_deprecated.to_epsg(20) + 4326 + >>> crs_latlon = CRS("+proj=latlon") + >>> crs_latlon.to_epsg(100) + >>> crs_latlon.to_epsg(70) + 4326 + >>> crs_epsg = CRS.from_epsg(4326) + >>> crs_epsg.to_epsg(100) + 4326 + >>> crs_wkt = CRS(crs_epsg.to_wkt()) + >>> crs_wkt.to_epsg(100) + 4326 + >>> crs_wkt == crs_epsg + True + >>> crs_epsg == crs_latlon + False + >>> crs_epsg == crs_deprecated + False + + +Internal PROJ Error ... SQLite error on SELECT +---------------------------------------------- + +The PROJ database is based on the EPSG database. With each release, +there is a good chance that there are database updates. If you have multiple +versions of PROJ installed on your systems and the search path for +the data directory becomes mixed up, you may see an error message like: +`SQLite error on SELECT`. This is likely due to a version of PROJ +attempting to use an incompatible database. + + +Debugging tips: + +- To get data directory being used: :func:`pyproj.datadir.get_data_dir` +- The order for searching for the data directory can be found in + the docstrings of :func:`pyproj.datadir.get_data_dir` +- To change the data directory: :func:`pyproj.datadir.set_data_dir` + + +.. _upgrade_transformer: + +Upgrading to pyproj 2 from pyproj 1 +----------------------------------- + +We recommended using the :class:`pyproj.transformer.Transformer` and +:class:`pyproj.crs.CRS` in place of the :class:`pyproj.Proj` and +:meth:`pyproj.transformer.transform`. + +Also see: + - :ref:`examples` + - :ref:`optimize_transformations` + +.. warning:: :meth:`pyproj.transformer.transform` and :meth:`pyproj.transformer.itransform` + are deprecated. + +pyproj 1 style: + + >>> from functools import partial + >>> from pyproj import Proj, transform + >>> proj_4326 = Proj(init="epsg:4326") + >>> proj_3857 = Proj(init="epsg:3857") + >>> transformer = partial(transform, proj_4326, proj_3857) + >>> transformer(12, 12) + + +pyproj 2 style: + + >>> from pyproj import Transformer + >>> transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857") + >>> transformer.transform(12, 12) diff --git a/3.7.0/_sources/history.rst.txt b/3.7.0/_sources/history.rst.txt new file mode 100644 index 000000000..c5be1d265 --- /dev/null +++ b/3.7.0/_sources/history.rst.txt @@ -0,0 +1,517 @@ +Change Log +========== + +3.7.0 +------ +- WHL: Wheels contain PROJ 9.4.1 (pull #1423) +- DEP: Minimum supported Python version 3.10 (pull #1357) +- DEP: Minimum PROJ version 9.2 (pull #1394) +- ENH: Add :meth:`CRS.is_deprecated` and :meth:`CRS.get_non_deprecated` (pull #1383) +- PERF: thread local context (issue #1133) +- ENH: Add runtime & compiled PROJ versions (discussion #1420) +- BUG: Handle changes to HotineObliqueMercatorBConversion (issue #1429) + +3.6.1 +------ +- WHL: Wheels contain PROJ 9.3.0 (issue #1327) +- BUG: Remove pkg_resources from setup.py (issue #1313) +- BUG: Cython 3 compatibility fixes (issue #1321) + +3.6.0 +------ +- DEP: Minimum supported Python version 3.9 (issue #1111) +- WHL: Wheels contain PROJ 9.2.1 (pull #1291) +- ENH: Added allow_superseded kwargs to :class:`pyproj.transformer.TransformerGroup` (pull #1269) +- ENH: Added :meth:`CRS.to_2d` to demote 3D CRS to 2D (issue #1266) +- ENH: Added parameter `output_axis_rule` to :meth:`CRS.to_wkt` (pull #1287) +- BUG: fix Geod.npts NaN handling (issue #1282) + +3.5.0 +------ +- DEP: Minimum PROJ version 9.0 (issue #1223) +- WHL: PROJ 9.2 in wheels (pull #1243) +- ENH: Add `return_back_azimuth: bool` to allow compatibility between the azimuth output of the following functions (issue #1163): + `fwd` and `fwd_intermediate`, `inv` and `inv_intermediate`, + Note: BREAKING CHANGE for the default value `return_back_azimuth=True` in the functions `fwd_intermediate` and `inv_intermediate` + to mach the default value in `fwd` and `inv` +- ENH: Added only_best kwarg to :meth:`.Transformer.from_crs` (issue #1228) +- PERF: Optimize point transformations (pull #1204) +- PERF: Optimize for single point in Geod fwd/inv functions (pull #1206) +- REF: Raise error when :meth:`.CRS.to_wkt`, :meth:`.CRS.to_json`, or :meth:`.CRS.to_proj4` returns None (issue #1036) +- CLN: Remove `AzumuthalEquidistantConversion` & :class:`LambertAzumuthalEqualAreaConversion`. :class:`AzimuthalEquidistantConversion` & :class:`LambertAzimuthalEqualAreaConversion` should be used instead (pull #1219) +- BUG: Fix Derived Projected CRS support (issue #1182) +- BUG: Add horizontal_datum_name for geographic CRS in :meth:`.CRS.to_cf` (issue #1251) +- BUG: Add datum ensemble support to :class:`.GeographicCRS` (pull #1255) + +3.4.1 +----- +- WHL: Add win32 to build_wheels matrix (pull #1169) +- BUG: Changed so that the setup.cfg depends on the version code in the __init__.py instead of the other way around (issuue #1155) +- BUG: Fix :meth:`.CRS.to_cf` for Pole rotation GRIB convention (pull #1167) +- BUG: Fix :meth:`.CRS.to_authority` memory leak (pull #1178) +- REF: Use upper case EPSG code when creating CRS (pull #1162) + +3.4.0 +----- +- WHL: Python 3.11 Wheels (issue #1110) +- WHL: Wheels contain PROJ 9.1.0 (pull #1132) +- DEP: Minimum PROJ version 8.2 (issue #1011) +- BUG: Fix transformer list for 3D transformations in :class:`.TransformerGroup` (discussion #1072) +- ENH: Added authority, accuracy, and allow_ballpark kwargs to :class:`.TransformerGroup` (pull #1076) +- ENH: Added ``force_over`` kwarg to :meth:`.Transformer.from_crs` (issue #997) +- ENH: Added :meth:`.Transformer.get_last_used_operation` (issue #1071) +- CLN: Remove deprecated ``skip_equivalent`` kwarg from transformers and ``errcheck`` kwarg from :meth:`.CRS.from_cf` (pull #1077) +- REF: use regex to process PROJ strings in :meth:`.CRS.to_dict` (pull #1086) +- BUG: :class:`.MercatorAConversion` defined only for lat_0 = 0 (issue #1089) +- BUG: Add support for `PROJ_DATA` environment variable (issue #1097) +- BUG: Ensure numpy masked arrays stay masked after projection (issue #1102) +- BLD: Don't specify runtime_library_dirs on Cygwin (pull #1120) +- BUG: Fix finding PROJ version with PROJ_LIB and PROJ 9.1+ (issue #1127) + +3.3.1 +------- +- WHL: Wheels for Linux are manylinux2014 (pip 19.3+) +- BUG: Complete database stub file with query_utm_crs_info() signature (issue #1044) +- BUG: Reorder deps in show_versions for setuptools issue (issue #1017) +- BUG: remove CustomConstructorCRS @abstractmethod decorator (pull #1018) +- BUG: Correct type annotation for AreaofUse.bounds (issue #1012) +- BUG: :func:`pyproj.datadir.get_data_dir` support for conda Windows (issue #1029) +- ENH: warn when :meth:`pyproj.crs.CRS.to_wkt`, :meth:`pyproj.crs.CRS.to_proj4`, or :meth:`pyproj.crs.CRS.to_json()` returns None (issue #1036) +- ENH: Added support for int-like strings and numpy dtypes (issues #1026 and #1835) +- ENH: Added support to pickle :class:`pyproj.transformer.Transformer` (issues #1058) + +3.3.0 +------- +- WHL: Wheels contain PROJ 8.2.0 +- DEP: Minimum supported Python version 3.8 (issue #930) +- DEP: Minimum PROJ version 8.0 (issue #940) +- BUG: Prepend "Derived" to CRS type name if CRS is derived (issue #932) +- BUG: Improved handling of inf values in :meth:`pyproj.transformer.Transformer.transform_bounds` (pull #961) +- BUG: CRS CF conversions mismatch of PROJ parameters in rotated pole (issue #948) +- ENH: Add support for transforming bounds at the poles in :meth:`pyproj.transformer.Transformer.transform_bounds` (pull #962) +- ENH: Added :attr:`pyproj.transformer.Transformer.source_crs` & :attr:`pyproj.transformer.Transformer.target_crs` (pull #976) +- ENH: Added :class:`pyproj.crs.coordinate_operation.PoleRotationNetCDFCFConversion` (issue #948) +- ENH: Added :func:`pyproj.database.get_database_metadata` (issue #990) +- ENH: Added PROJ database metadata to :func:`pyproj.show_versions` (issue #990) + +3.2.1 +------ +- REF: declare specific python types in cython (pull #928) +- REF: Use cython string decoding (pull #929) +- BUG: Return multiple authorities with :attr:`pyproj.crs.CRS.list_authority` (pull #943) +- BUG: CRS CF conversions ensure lon_0 = north_pole_grid_longitude + 180 (issue #927) +- BUG: CRS CF conversions ensure Pole rotation (netCDF CF convention) conversion works (issue #927) + +3.2.0 +------ +- WHL: Wheels contain PROJ 8.1.1 +- DOC: Add new pyproj logo (issue #700) +- REF: Handle deprecation of proj_context_set_autoclose_database (issue #866) +- REF: Make CRS methods inheritable (issue #847) +- ENH: Added :attr:`pyproj.crs.CRS.is_derived` (pull #902) +- ENH: Added :attr:`pyproj.crs.GeocentricCRS` (pull #903) +- ENH: Added :attr:`pyproj.crs.CRS.list_authority` (issue #918) +- ENH: Added `inplace` kwarg to :meth:`pyproj.transformer.Transformer.transform` (issue #906) +- PERF: Disable unnecessary copy in dtype conversion for buffer (pull #904) +- DOC: Improve FAQ text about CRS formats (issue #789) +- BUG: Add PyPy cython array implementation (issue #854) +- BUG: Fix spelling for + :class:`pyproj.crs.coordinate_operation.AzimuthalEquidistantConversion` + and :class:`pyproj.crs.coordinate_operation.LambertAzimuthalEqualAreaConversion` (issue #882) +- BUG: Make datum name match exact in :func:`pyproj.database.query_utm_crs_info` (pull #887) +- BUG: Update :class:`pyproj.enums.GeodIntermediateFlag` for future Python compatibility (issue #855) +- BUG: Hide unnecessary PROJ ERROR from proj_crs_get_coordoperation (issue #873) +- BUG: Fix pickling for CRS builder classes (issue #897) +- CLN: Remove `ignore_axis_order` kwarg from :meth:`pyproj.crs.CRS.is_exact_same` as it was added by accident (pull #904) +- CLN: remove numeric/numarrays support (pull #908) +- LNT: Add pylint & address issues (pull #909) +- DEP: Remove distutils dependency (pull #917) + +3.1.0 +----- +* WHL: Wheels contain PROJ 8.0.1 +* DEP: Minimum supported Python version 3.7 (issue #790) +* REF: Multithread safe CRS, Proj, & Transformer (issue #782) +* BUG: Disallow NaN values with AreaOfInterest & BBox (issue #788) +* ENH: Pretty format PROJ string support (issue #764) +* ENH: Added :meth:`pyproj.transformer.Transformer.to_proj4` (pull #798) +* ENH: Added authority, accuracy, and allow_ballpark kwargs to :meth:`pyproj.transformer.Transformer.from_crs` (issue #754) +* ENH: Added support for "AUTH:CODE" input to :meth:`pyproj.transformer.Transformer.from_pipeline` (issue #755) +* ENH: Added :meth:`pyproj.crs.CRS.to_3d` (pull #808) +* ENH: Added :meth:`pyproj.transformer.Transformer.transform_bounds` (issue #809) +* ENH: Added :attr:`pyproj.crs.CRS.is_compound` (pull #823) +* ENH: Added `initial_idx` and `terminal_index` kwargs to :meth:`pyproj.Geod.npts` (pull #841) +* ENH: Added :meth:`pyproj.Geod.inv_intermediate` & :meth:`pyproj.Geod.fwd_intermediate` (pull #841) +* REF: Skip transformations if `noop` & deprecate `skip_equivalent` (pull #824) + +3.0.1 +----- +* WHL: Wheels contain PROJ 7.2.1 +* Use `proj_context_errno_string` in PROJ 8+ due to deprecation (issue #760) +* BUG: Allow transformations with empty arrays (issue #766) +* BUG: support numpy objects in CRS.from_cf (issue #773) + +3.0.0 +----- +* Minimum supported Python version 3.6 (issue #499) +* Minimum PROJ version 7.2 (issues #599 & #689) +* WHL: Removed datumgrids from wheels because not needed with RFC 4 (pull #628) +* WHL: Wheels contain PROJ 7.2 +* ENH: Added :ref:`network_api` (#675, #691, #695) +* ENH: Added ability to use global context (issue #661) +* ENH: Added transformation grid sync API/CLI (issue #572) +* ENH: Support objects with '__array__' method (pandas.Series, xarray.DataArray, dask.array.Array) (issue #573) +* ENH: Added :func:`pyproj.datadir.get_user_data_dir` (pull #636) +* ENH: Added :attr:`pyproj.transformer.Transformer.is_network_enabled` (issue #629) +* ENH: Added :meth:`pyproj.transformer.TransformerGroup.download_grids` (pull #643) +* ENH: Use 'proj_get_units_from_database' in :func:`pyproj.database.get_units_map` & cleanup :func:`pyproj.database.get_codes` (issue #619) +* ENH: Added support for radians for Proj & Transformer.from_pipeline & use less gil (issue #612) +* ENH: Datum.from_name default to check all datum types (issue #606) +* ENH: Use from_user_input in __eq__ when comparing CRS sub-classes (i.e. PrimeMeridian, Datum, Ellipsoid, etc.) (issue #606) +* ENH: Add support for coordinate systems with CRS using CF conventions (issue #536) +* ENH: Use `proj_is_equivalent_to_with_ctx` in the place of `proj_is_equivalent_to` internally (issue #666) +* BUG: Add support for identifying engineering/parametric/temporal datums (issue #670) +* ENH: Add support for temporal CRS CF coordinate system (issue #672) +* ENH: Added support for debugging internal PROJ (pull #696) +* ENH: Added pathlib support for data directory methods (pull #702) +* ENH: Added :func:`pyproj.database.query_crs_info` (pull #703) +* ENH: Added :func:`pyproj.database.query_utm_crs_info` (pull #712) +* REF: Refactor Proj to inherit from Transformer (issue #624) +* REF: Added `pyproj.database`, `pyproj.aoi`, and `pyproj.list` modules (pull #703) +* BUG: Fix handling of polygon holes when calculating area in Geod (pull #686) + +2.6.1 +~~~~~ +* WHL: Wheels contain PROJ version is 7.0.1 +* BUG: Allow `*_name` to be added in CRS.to_cf (issue #585) +* BUG: Fix building prime meridian in :meth:`pyproj.crs.CRS.from_cf` (pull #588) +* BUG: Fix check for numpy bool True kwarg (pull #590) +* DOC: Update pyproj.Proj docstrings for clarity (issue #584) +* Added `pyproj.__proj_version__` +* BUG: Fix :meth:`pyproj.Proj.get_factors` (issue #600) +* BUG: fix unequal (!=) with non-CRS type (pull #596) + +2.6.0 +~~~~~ +* ENH: Added :meth:`pyproj.Proj.get_factors` (issue #503) +* ENH: Added type hints (issue #369) +* BUG: Don't use CRS classes for defaults in CRS child class init signatures (issue #554) +* ENH: Updated :attr:`pyproj.crs.CRS.axis_info` to pull all relevant axis information from CRS (issue #557) +* ENH: Added :meth:`pyproj.transformer.Transform.__eq__` (issue #559) +* ENH: Added :attr:`pyproj.crs.CRS.utm_zone` (issue #561) +* BUG: Modify CRS dict test to accommodate numpy bool types. (issue #564) +* BUG: Fix pipeline transformations to match cct (issue #565) +* BUG: Don't silently ignore kwargs when projparams are specified (Proj & CRS) (issue #565) + +2.5.0 +~~~~~ +* WHL: Wheels contain PROJ version is 6.3.1 +* Remove deprecated PyObject_AsWriteBuffer (issue #495) +* ENH: Added :meth:`pyproj.crs.CRS.equals` with `ignore_axis_order` kwarg (issue #493) +* ENH: Added :meth:`pyproj.crs.CoordinateSystem.from_json`, :meth:`pyproj.crs.CoordinateSystem.from_json_dict`, and :meth:`pyproj.crs.CoordinateSystem.from_string` (pull #501) +* ENH: Added :class:`pyproj.crs.CoordinateSystem` to `pyproj.crs` namespace (pull #501) +* ENH: Added :meth:`pyproj.crs.CoordinateSystem.from_user_input`, :meth:`pyproj.crs.CoordinateOperation.from_user_input`, :meth:`pyproj.crs.Datum.from_user_input`, :meth:`pyproj.crs.PrimeMeridian.from_user_input`, :meth:`pyproj.crs.Ellipsoid.from_user_input` (pull #502) +* ENH: Added :meth:`pyproj.crs.CoordinateSystem.from_name`, :meth:`pyproj.crs.CoordinateOperation.from_name`, :meth:`pyproj.crs.Datum.from_name`, :meth:`pyproj.crs.PrimeMeridian.from_name`, :meth:`pyproj.crs.Ellipsoid.from_name` (pull #505) +* BUG: Fix getting :attr:`pyproj.crs.Ellipsoid.semi_minor_metre` when not computed (issue #457) +* ENH: Added support for custom CRS (issue #389) +* ENH: Added enumeration for WKT2_2019 (issue #526) +* ENH: Update from_cf/to_cf to use WKT instead of PROJ strings for internal management (issue #515) + +2.4.2 +~~~~~ +* Elevate +init= warning to FutureWarning (pull #486) +* Add UserWarning to :meth:`pyproj.crs.CRS.to_proj4` (pull #486) +* BUG: Fix for 32-bit i686 platforms (issue #481) +* Return 'inf' in Proj instead of 1.e30 (pull #491) + +2.4.1 +~~~~~ +* WHL: Wheels contain PROJ version is 6.2.1 (issue #456) +* WHL: Wheels for Linux x86_64 use manylinux2010 (pyproj4/pyproj-wheels/pull/18) +* BUG: Fix setting lat_ts for mercator projection in :meth:`pyproj.crs.CRS.from_cf` and :meth:`pyproj.crs.CRS.to_cf` (issue #461) +* BUG: latlon -> longlat in `CRS.from_cf()` for o_proj so behavior consistent in PROJ 6.2.0 and 6.2.1 (pull #472) +* ENH: Add repr for `pyproj.crs.CoordinateOperation` and for `pyproj.transformer.TransformerGroup` (pull #464) + +2.4.0 +~~~~~ +* Minimum PROJ version is 6.2.0 (issue #411) +* Removed global pyproj context (issue #418) +* Added support for PROJ JSON in `pyproj.crs` objects and `pyproj.Transformer` (pull #432) +* Moved doctests code out of `pyproj.__init__` (issue #417) +* Added version information to `python -m pyproj` (pull #429) +* Added `scope` & `remarks` to `pyproj.crs` objects and `pyproj.Transformer` (issue #441) +* Added `operations` to `pyproj.crs.CoordinateOperation` objects and `pyproj.Transformer` (issue #441) +* Added :func:`pyproj.get_authorities` and :func:`pyproj.get_codes` (issue #440) +* Release gil in core cython/PROJ code (issue #386) +* BUG: Added checks for uninitialized `pyproj.crs` objects to prevent core dumping (issue #433) +* BUG: Added fix for get_transform_crs when checking type (pull #439) +* DOC: Build docs with python3 (pull #428) + +2.3.1 +~~~~~ +* Added cleanup for internal PROJ errors (issue #413) +* Delay checking for pyproj data directory until importing pyproj (issue #415) +* Address issue where PROJ core dumps on proj_create with +init= when global context does not have data directory set (issue #415 & issue #368) + +2.3.0 +~~~~~ +* Minimum supported Python version 3.5 (issue #331) +* New `pyproj.geod.Geod` additions: + * Added support for calculating geodesic area (:meth:`pyproj.Geod.polygon_area_perimeter`) + and added interface to calculate total length of a line + (:meth:`pyproj.Geod.line_length` & :meth:`pyproj.Geod.line_lengths`) (issue #210). + * Added support for calculating geodesic area and line lengths with shapely geometries + (:meth:`pyproj.Geod.geometry_area_perimeter` & :meth:`pyproj.Geod.geometry_length`) + (pull #366) +* New `pyproj.transformer` additions: + * Added :class:`pyproj.transformer.TransformerGroup` to make all transformations available (issue #381) + * Added option for `area_of_interest` for :meth:`pyproj.transformer.Transformer.from_crs`, + :meth:`pyproj.transformer.Transformer.from_proj` and :class:`pyproj.transformer.TransformerGroup` + * Added :attr:`pyproj.transformer.Transformer.area_of_use` (issue #385) +* Added :attr:`pyproj.crs.CoordinateOperation.area_of_use` (issue #385) +* Updated to only have one PJ_CONTEXT per pyproj session (issue #374) +* Always return latlon with Proj (issue #356) +* Remove aenum dependency (issue #339) +* Removed deprecated functions `Proj.proj_version`, `CRS.is_valid`, and `CRS.to_geodetic()` (pull #371) +* Search on `sys.prefix` for the PROJ data directory (issue #387) + +2.2.2 +~~~~~ +* Update wheels to PROJ 6.1.1 +* Add deprecation warning when using +init= syntax (pull #358) +* Added :meth:`pyproj.crs.is_proj` (pull #359) +* Fixed case in :meth:`pyproj.crs.CRS.to_dict` with :meth:`pyproj.crs.CRS.to_proj4` returning None (pull #359) +* Keep `no_defs` in input PROJ string as it does not hurt/help anything in current code (pull #359) +* Made public properties on C classes readonly (pull #359) +* Update data dir exception handling to prevent ignoring errors (pull #361) +* :meth:`pyproj.crs.CRS.to_cf` export transverse mercator parameters for UTM zones (pull #362) + +2.2.1 +~~~~~ +* Added :meth:`pyproj.show_versions` (issue #334) +* Added fix for whitepace around '=' in PROJ strings (issue #345) +* Update version check in `setup.py` (issue #323) +* Add "stable" doc site pointing to latest release (issue #347, pull #348) +* Deprecate `Proj.proj_version` (pull #337) +* Test fixes (pull #333, pull #335) + +2.2.0 +~~~~~ +* Minimum PROJ version is now 6.1.0 +* `pyproj.crs` updates: + * Updated CRS repr (issue #264) + * Add Datum, CoordinateSystem, CoordinateOperation classes, (issue #262) + * Added :meth:`pyproj.crs.CRS.to_cf` and :meth:`pyproj.crs.CRS.from_cf` for + converting to/from Climate and Forecast (CF) 1.8 grid mappings (pull #244) + * Added :meth:`pyproj.crs.CRS.to_dict` (issue #226) + * Added :meth:`pyproj.crs.CRS.to_authority` (pull #294) + * Added :attr:`pyproj.crs.CRS.is_vertical` and :attr:`pyproj.crs.CRS.is_engineering` (issue #316) + * Added :attr:`pyproj.crs.CRS.target_crs` (pull #328) + * Provide option to "pretty print" WKT in :attr:`pyproj.crs.CRS.to_wkt` (issue #258) + * Add support for Bound and Compound CRS for :attr:`pyproj.crs.CRS.is_geographic`, :attr:`pyproj.crs.CRS.is_projected` (issue #274) + * Add support for Bound CRS for :attr:`pyproj.crs.CRS.is_geocentric` (issue #374) + * Add support for comparison with CRS a non-crs type supported by :meth:`pyproj.crs.CRS.from_user_input` (issue #312) + * Added support for ITRF, compound EPSG, and urn projection strings in CRS (pull #289) + * Better handle Compound CRS (issue #265) + * Disallow creation of non-CRS object (eg pipeline) in CRS class (issue #267) + * Added check in :meth:`pyproj.crs.CRS.to_epsg` for when `proj_list` is null (issue #257) + * Fix comparing classes of non-instance types (issue #310) +* `pyroj.transformer` updates: + * Added `always_xy` option to Transformer so the transform method will + always accept as input and return as output coordinates using the + traditional GIS order, that is longitude, latitudecfor geographic + CRS and easting, northing for most projected CRS (issue #225) + * Provide `direction` option in :meth:`pyproj.transformer.Transformer.transform` (issue #266) + * Add check for valid initialization of Transformer and ensure it is a transformer (issue #321) + * Added :meth:`pyproj.transformer.Transformer.to_wkt` as well as attributes related to `PJ_PROJ_INFO` (pull #322) + * Undo deprecation of :meth:`pyproj.transformer.Transformer.from_crs` (issue #275) + * Fix false positive errors raised in transformer (issue #249) +* Fix :class:`pyproj.Proj` initialization from DerivedGeographicCRS (issue #270) +* Add interface to get the projection/ellps/prime_meridian/units lists (issue #251) +* Docs/Build/Test fixes (pull #278, pull #245, pull #248, pull #247, issue #253, pull #252) + +2.1.3 +~~~~~ +* Added support for time transformations (issue #208) +* Fixed projection equivalence testing for transformations (pull #231). +* Switch to pytest for testing (pull #230) +* Various testing fixes (pull #223, #222, #221, #220) +* Convert PROJ error messages from bytes to strings (pull #219) +* Fix data dir path separator to be (;) for windows and (:) for linux (pull #234) + +2.1.2 +~~~~~ +* Updated to use the CRS definition for Proj instances in transforms (issue #207) +* Add option to skip transformation operation if input and output projections are equivalent + and always skip if the input and output projections are exact (issue #128) +* Update setup.py method for checking PROJ version (pull #211) +* Add internal proj error log messages to exceptions (pull #215) + +2.1.1 +~~~~~ +* Restore behavior of 1.9.6 when illegal projection transformation requested + (return ``inf`` instead of raising an exception, issue #202). kwarg ``errcheck`` + added to :func:`pyproj.transformer.transform` and :func:`pyproj.transformer.itransform` + (default ``False``). When ``errcheck=True`` an exception is raised. + +2.1.0 +~~~~~ +* Added :class:`pyproj.transformer.Transformer` to make repetitive transformations more efficient (issue #187) +* Added fix for using local datumgrids with transform (issue #191) +* Added :meth:`pyproj.transformer.Transformer.from_pipeline` to support pipeline transformations. +* Added fix for conversion between radians/degrees for transformations (issues #192 & #195) + +2.0.2 +~~~~~ +* add filter for boolean values in dict2string so "no_rot=True" works (issue #183). +* make sure .pxd files included in source tarball. +* add radians flag back in for transform/itransform (issue #185). + +2.0.1 +~~~~~ +* Ensure data path set properly for TransProj (pull request #179, addressed + issue #176). + +2.0.0 +~~~~~ +* Update to PROJ version 6.0.0 & removed support for older PROJ versions. +* Added pyproj.CRS class. +* Updated pyproj.Proj & pyproj.transform to accept any input from CRS.from_user_input. +* Removed internal PROJ source code. +* Changed default for preserve_units to be True in pyproj.Proj class initialization. +* Modified logic for searching for the PROJ data directory to not conflict with older versions of PROJ. +* Added pyproject.toml. + +1.9.6 +~~~~~ +* fix segfault when inverse projection not defined (issue #43, pull request + #44). +* supports python 3.7 + +1.9.5.1 +~~~~~~~ +* fix for issue #42 (compilation error with microsoft visual studio). + +1.9.5 +~~~~~ +* update proj4 source to latest github master (commit 953cc00fd87425395cabe37641cda905c4b587c1). +* port of basemap fix for input arrays in fortran order +* restore inverse Hammer patch that was lost when proj4 source code was updated. + +1.9.4 (git tag v1.9.4rel) +~~~~~~~~~~~~~~~~~~~~~~~~~ + * migrate to github from googlecode. + * update proj4 source code from svn r2595 (version 4.9.0RC2). + * include runtime_library_dirs in setup-proj.py. + * added to_latlong method (issue 51). + * fix back azimuth when lon1 and lon2 are identical. + +1.9.3 (svn revision 327) +~~~~~~~~~~~~~~~~~~~~~~~~ + * Geod now uses C code adapted from geographiclib now included in proj4 source, + instead of pure python code directly from geographiclib. + * make radians=True work with Geod.npts (issue 47). + * allow PROJ_DIR env var to control location of proj data (issue 40). + +1.9.2 (svn revision 301) +~~~~~~~~~~~~~~~~~~~~~~~~ + * updated proj4 src to 4.8.0 - includes two new map projections (natearth and + isea). + +1.9.1 (svn revision 285) +~~~~~~~~~~~~~~~~~~~~~~~~ + * restore compatibility with python 2.4/2.5, which was broken by the addition + of the geographiclib geodesic module (issue 36). + +1.9.0 (svn revision 282) +~~~~~~~~~~~~~~~~~~~~~~~~ + * use pure python geographiclib for geodesic computation codes instead of proj4. + * don't use global variable pj_errno for return codes, use pj_ctx_get_errno instead. + * use new projCtx structure for thread safety in proj lib. + * update C source and data from proj4 svn (r2140). + * add pj_list and pj_ellps module level variables (a dict mapping short names to longer descriptions, e.g. pyproj.pj_list['aea'] = 'Albers Equal Area'). + +1.8.9 (svn revision 222) +~~~~~~~~~~~~~~~~~~~~~~~~ + * Python 3 now supported. + * allow 'EPSG' init (as well as 'epsg'). This only worked on case-insensitive + filesystems previously. Fixes issue 6. + * added inverse to Hammer projection. + * updated proj.4/src/pj_mutex.c from proj4 svn to fix a threading issue on windows + (issue 25). Windows binary installers updated (version 1.8.8-1), courtesy + Christoph Gohlke. + * if inputs are NaNs, return huge number (1.e30). + +1.8.8 (svn revision 196) +~~~~~~~~~~~~~~~~~~~~~~~~ + * add extra datum shift files, added test/test_datum.py (fixes issue 22). + datum shifts now work correctly in transform function. + +1.8.7 (svn revision 175) +~~~~~~~~~~~~~~~~~~~~~~~~ + * reverted pj_init.c to old version (from proj4 4.6.1) because version in + 4.7.0 includes caching code that can cause segfaults in pyproj (issue 19). + * added 'preserve_units' keyword to Proj.__init__ to suppress conversion + to meters. + +1.8.6 (svn revision 169) +~~~~~~~~~~~~~~~~~~~~~~~~ + * now works with ms vs2008, vs2003 (fixed missing isnan). + * updated to proj 4.7.0 (fixes a problem coexisting with pyqt). + * allow Geod instance to be initialized using a proj4 string + +1.8.5 (svn revision 155) +~~~~~~~~~~~~~~~~~~~~~~~~ + * allow Proj instance to be initialized using a proj4 string + (instead of just a dict or kwargs). + +1.8.4 (svn revision 151) +~~~~~~~~~~~~~~~~~~~~~~~~ + * updated proj4 sources to version 4.6.0 + +1.8.3 (svn revision 146) +~~~~~~~~~~~~~~~~~~~~~~~~ + * fixed bug in Geod class that caused erroneous error message + "undefined inverse geodesic (may be an antipodal point)". + * fix __reduce__ method of Geod class so instances can be pickled. + * make sure points outside projection limb are set to 1.e30 on inverse + transform (if errcheck=False). + * fixed small setup.py bug. + * generate C source with Cython 0.9.6.6 (pycompat.h no longer needed). + +1.8.2 +~~~~~ + * added 'srs' (spatial reference system) instance variable to Proj. + * instead of returning HUGE_VAL (usually 'inf') when projection not defined + and errcheck=False, return 1.e30. + * added Geod class for geodesic (i.e. Great Circle) computations. + Includes doctests (which can be run with pyproj.test()). + * proj.4 source code now included, thus removing proj.4 lib + dependency. Version 4.5.0 is included, with a patch to + create an API for geodesic computations. + * python 2.4 compatibility patch (suggested by Andrew Straw) + from M. v. Loewis: + http://mail.python.org/pipermail/python-dev/2006-March/062561.html + +1.8.1 +~~~~~ + * if given tuples, returns tuples (instead of lists). + * test for numpy arrays first. + * Fixed error in docstring example. + * README.html contains html docstrings generated by pydoc. + * Renamed pyproj.so to _pyproj.so, created a new python module + called pyproj.py. Moved as code as possible from _pyproj.so to + pyproj.py. + * docstring examples now executed by doctest when 'pyproj.test()' is run. + * added test to _pyproj.c which defines Py_ssize_t for python < 2.5. + This is necessary when pyrex 0.9.5 is used. + +1.8.0 +~~~~~ + * Better error handling Proj.__init__. + * Added optional keyword 'errcheck' to __call__ method. + * If True, an exception is raised if the transformation is invalid. + +1.7.3 +~~~~~ + * python 2.5 support. diff --git a/3.7.0/_sources/index.rst.txt b/3.7.0/_sources/index.rst.txt new file mode 100644 index 000000000..53aca1ef1 --- /dev/null +++ b/3.7.0/_sources/index.rst.txt @@ -0,0 +1,40 @@ +pyproj Documentation +==================== + +Python interface to `PROJ `_ (cartographic projections and coordinate transformations library). + +GitHub Repository: https://github.com/pyproj4/pyproj + +.. note:: Minimum supported PROJ version is 9.0 + +.. note:: Minimum supported Python version is 3.10 + +.. note:: Linux (manylinux2014) wheels require pip 19.3+ + +.. note:: pyproj 3 wheels do not include transformation grids. + For migration assistance see: :ref:`transformation_grids` + + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + installation + examples + transformation_grids + gotchas + api/index + cli + advanced_examples + build_crs + build_crs_cf + crs_compatibility + optimize_transformations + history + past_versions + +Indices and tables +================== +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/3.7.0/_sources/installation.rst.txt b/3.7.0/_sources/installation.rst.txt new file mode 100644 index 000000000..367aeb2cd --- /dev/null +++ b/3.7.0/_sources/installation.rst.txt @@ -0,0 +1,200 @@ +.. highlight:: shell + +============ +Installation +============ + +The easiest methods for installing pyproj are: + +1. Use pip to install the binary wheels from `PyPI `__: + + .. code-block:: bash + + python -m pip install pyproj + + .. note:: Linux (manylinux2014) wheels require pip 19.3+ + + .. note:: pyproj 3+ wheels do not include transformation grids. + For migration assistance see: :ref:`transformation_grids` + + + - The MacOS and Linux wheels are powered by + `cibuildwheel `__ + & `multibuild `__ + - The Windows wheels versions <= 3.3.x were built by `Christoph Gohlke `__ + + +2. Use `conda `__ with the `conda-forge `__ channel: + + .. code-block:: bash + + conda config --prepend channels conda-forge + conda config --set channel_priority strict + conda create -n pyproj_env pyproj + conda activate pyproj_env + + .. note:: + "... we recommend always installing your packages inside a + new environment instead of the base environment from + anaconda/miniconda. Using envs make it easier to + debug problems with packages and ensure the stability + of your root env." + -- https://conda-forge.org/docs/user/tipsandtricks.html + + .. warning:: + Avoid using `pip install` with a conda environment. If you encounter + a python package that isn't in conda-forge, consider submitting a + recipe: https://github.com/conda-forge/staged-recipes/ + + + - `pyproj` is maintained by the `pyproj-feedstock maintainers `__ + - `PROJ` is maintained by the `proj.4-feedstock maintainers `__ + +If these installation methods do not meet your needs, the section below provides further instructions +for getting setup. + +3. Install nightly wheels from anaconda: + +.. code-block:: python + + python -m pip install pyproj --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple + +Transformation Grids +===================== + +See: :ref:`transformation_grids` + + +Installing from source +====================== + +Version compatibility matrix: + +============ ============ +pyproj PROJ +============ ============ +<= 1.9.6 <= 5.2 +2.0-2.1 6.0-7 +2.2-2.3 6.1-7 +2.4-2.6 6.2-7 +3.0.0 7.2 +3.0.1-3.2 7.2-9.1 +3.3 8.0-9.1 +3.4+ 8.2+ +3.5+ 9+ +3.7+ 9.2+ +============ ============ + +Setup PROJ +------------ + +PROJ is required when building from source. + +:ref:`PROJ Installation Instructions ` + +You can also download PROJ from: + +- https://download.osgeo.org/proj +- https://github.com/OSGeo/PROJ + + +pyproj Build Environment Variables +----------------------------------- + +.. envvar:: PROJ_VERSION + + .. versionadded:: 3.0 + + This sets the version of PROJ when building pyproj. This + enables installing pyproj when the PROJ executables are not + present but the header files exist. + +.. envvar:: PROJ_DIR + + This is the path to the base directory for PROJ. + Examples of how to set the PROJ_DIR environment variable: + + Windows:: + + set PROJ_DIR=C:\OSGeo4W\ + + Linux:: + + export PROJ_DIR=/usr/local + +.. envvar:: PROJ_LIBDIR + + This is the path to the directory containing the PROJ libraries. + If not set, it searches the `lib` and `lib64` directories inside + the PROJ directory. + +.. envvar:: PROJ_INCDIR + + This is the path to the PROJ include directory. If not set, it assumes + it is the `includes` directory inside the PROJ directory. + +.. envvar:: PROJ_WHEEL + + This is a boolean value used when building a wheel. When true + it includes the contents of the `pyproj/proj_dir/proj/share` + directory if present. + +.. envvar:: PYPROJ_FULL_COVERAGE + + Boolean that sets the compiler directive for cython to include + the test coverage. + + +Setup pyproj +------------ + +In the setup.py, the order for searching for PROJ is: + + 1. The :envvar:`PROJ_DIR` environment variable + 2. The internal PROJ directory (pyproj/proj_dir) + 3. The `proj` executable in sys.prefix + 4. The `proj` executable on the PATH + +For best results, set the :envvar:`PROJ_DIR` environment variable to +point to location of PROJ installation before running setup.py. + +If you have a previous version of PROJ installed alongside the current +version of PROJ, the best way to avoid conflicts is to: + + 1. Remove the previous PROJ from `PATH` & unset the `PROJ_DATA`` (PROJ 9.1+) | `PROJ_LIB` (PROJ<9.1) environment variables (temporarily) + 2. Install PROJ to the internal PROJ directory (pyproj/proj_dir) + 3. Set the environment variable :envvar:`PROJ_DIR` to point to the internal PROJ directory + 4. Set the environment variable :envvar:`PROJ_WHEEL` to true + 5. Build pyproj + + +Install pyproj +~~~~~~~~~~~~~~ + +.. note:: `Cython `_ or pip>=10.0.1 is required for the installation. + +.. note:: You may need to run pip with administrative privileges (e.g. `sudo pip`) or + perform a user only installation (e.g. `pip install --user`). + + +From pypi: +^^^^^^^^^^ + +.. code-block:: bash + + pip install pyproj --no-binary pyproj + + +From GitHub with `pip`: +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + pip install git+https://github.com/pyproj4/pyproj.git + +From cloned GitHub repo for development: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + pip install -e . diff --git a/3.7.0/_sources/optimize_transformations.rst.txt b/3.7.0/_sources/optimize_transformations.rst.txt new file mode 100644 index 000000000..765957953 --- /dev/null +++ b/3.7.0/_sources/optimize_transformations.rst.txt @@ -0,0 +1,6 @@ +.. _optimize_transformations: + +Optimize Transformations +======================== + +Moved to: :ref:`advanced_examples` diff --git a/3.7.0/_sources/past_versions.rst.txt b/3.7.0/_sources/past_versions.rst.txt new file mode 100644 index 000000000..451035350 --- /dev/null +++ b/3.7.0/_sources/past_versions.rst.txt @@ -0,0 +1,17 @@ +Documentation Archive +===================== + +- `3.6.1 `_ +- `3.5.0 `_ +- `3.4.1 `_ +- `3.3.1 `_ +- `3.2.1 `_ +- `3.1.0 `_ +- `3.0.1 `_ +- `2.6.1 `_ +- `2.5.0 `_ +- `2.4.2 `_ +- `2.3.1 `_ +- `2.2.2 `_ +- `2.1.3 `_ +- `1.9.6 `_ diff --git a/3.7.0/_sources/transformation_grids.rst.txt b/3.7.0/_sources/transformation_grids.rst.txt new file mode 100644 index 000000000..cbdd633c0 --- /dev/null +++ b/3.7.0/_sources/transformation_grids.rst.txt @@ -0,0 +1,121 @@ +.. _transformation_grids: + +Transformation Grids +===================== + +Transformation grids improve accuracy when you are performing datum transformations. + +More information about the data available is located under the PROJ +:ref:`resource files ` documentation. + +.. note:: `pyproj` API for managing the :ref:`data_directory` and :ref:`network_api`. + +.. note:: pyproj 3 wheels do not include any transformation grids. + + +Downloading data +---------------- + +PROJ 7+ +^^^^^^^^ + +PROJ 7.0 has introduced, per +:ref:`PROJ RFC 4: Remote access to grids and GeoTIFF grids `, +the capability to work with grid files that are not installed on the local machine where PROJ is executed. + +Available methods for download include: + +- `Mirroring the data `__: + + To download to the PROJ user-writable data directory: + + .. versionadded:: 7.1.0 + + .. code-block:: bash + + export PROJ_DOWNLOAD_DIR=$(python -c "import pyproj; print(pyproj.datadir.get_user_data_dir())") + + To download to the main PROJ data directory: + + .. code-block:: bash + + export PROJ_DOWNLOAD_DIR=$(python -c "import pyproj; print(pyproj.datadir.get_data_dir())") + + Download the files with either: + + .. code-block:: bash + + aws s3 sync s3://cdn.proj.org ${PROJ_DOWNLOAD_DIR} + + or: + + .. code-block:: bash + + wget --mirror https://cdn.proj.org/ -P ${PROJ_DOWNLOAD_DIR} + +- The :ref:`projsync ` command line program. + +- `pyproj sync `__ command line program (pyproj 3+; useful if you use pyproj wheels). + +- Enabling :ref:`PROJ network ` capabilities. See also :ref:`network_api`. + +- Download stable from https://download.osgeo.org/proj or latest from https://github.com/OSGeo/PROJ-data + +- Use `conda `__ with the `conda-forge `__ channel: + + .. code-block:: bash + + conda install -c conda-forge proj-data + + +PROJ <= 6 +^^^^^^^^^^ + +Available methods for download include: + +- Download stable from https://download.osgeo.org/proj or latest from https://github.com/OSGeo/proj-datumgrid + +- Use `conda `__ with the `conda-forge `__ channel: + + .. code-block:: bash + + conda install -c conda-forge proj-datumgrid-europe proj-datumgrid-north-america proj-datumgrid-oceania proj-datumgrid-world + + +What grids to download? +----------------------- + +- Only using the :obj:`pyproj.crs.CRS` or :obj:`pyproj.Geod` classes? Then no grids are needed. + +- Have a machine that can hold and extra 500 MB - 1 GB of data? Then downloading all grids shouldn't be an issue. + +- Have a machine with limited space, a great network connection, and PROJ 7+? + Look into `PROJ network `__ capabilities. See also :ref:`network_api`. + +- Have a machine with limited space and want to pre-download files? + + You can enable enable :ref:`debugging-internal-proj` with pyproj 3+ and perform a transformation. + The logs will show the grids PROJ searches for. + + Additionally, the :class:`pyproj.transformer.TransformerGroup` can assist finding the grids you need to download. + + .. warning:: There are cases where the URL to download the grid is missing. + + .. code-block:: python + + >>> from pyproj.transformer import TransformerGroup + >>> tg = trans_group = TransformerGroup(4326, 2964) + UserWarning: Best transformation is not available due to missing Grid(short_name=us_noaa_alaska.tif, full_name=, package_name=, url=https://cdn.proj.org/us_noaa_alaska.tif, direct_download=True, open_license=True, available=False) + >>> tg + + - transformers: 8 + - unavailable_operations: 2 + >>> tg.transformers[0].description + 'Inverse of NAD27 to WGS 84 (7) + Alaska Albers' + >>> tg.unavailable_operations[0].name + 'Inverse of NAD27 to WGS 84 (85) + Alaska Albers' + >>> tg.unavailable_operations[0].grids[0].url + 'https://cdn.proj.org/us_noaa_alaska.tif' + >>> tg.download_grids(verbose=True) # pyproj 3+ + Downloading: https://cdn.proj.org/us_noaa_alaska.tif + Downloading: https://cdn.proj.org/ca_nrc_ntv2_0.tif diff --git a/3.7.0/_static/basic.css b/3.7.0/_static/basic.css new file mode 100644 index 000000000..f316efcb4 --- /dev/null +++ b/3.7.0/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/3.7.0/_static/debug.css b/3.7.0/_static/debug.css new file mode 100644 index 000000000..74d4aec33 --- /dev/null +++ b/3.7.0/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/3.7.0/_static/doctools.js b/3.7.0/_static/doctools.js new file mode 100644 index 000000000..4d67807d1 --- /dev/null +++ b/3.7.0/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/3.7.0/_static/documentation_options.js b/3.7.0/_static/documentation_options.js new file mode 100644 index 000000000..64c1f5e81 --- /dev/null +++ b/3.7.0/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '3.7.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/3.7.0/_static/file.png b/3.7.0/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/3.7.0/_static/file.png differ diff --git a/3.7.0/_static/icon.png b/3.7.0/_static/icon.png new file mode 100644 index 000000000..583ea4493 Binary files /dev/null and b/3.7.0/_static/icon.png differ diff --git a/3.7.0/_static/language_data.js b/3.7.0/_static/language_data.js new file mode 100644 index 000000000..367b8ed81 --- /dev/null +++ b/3.7.0/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/3.7.0/_static/logo.png b/3.7.0/_static/logo.png new file mode 100644 index 000000000..c11764a96 Binary files /dev/null and b/3.7.0/_static/logo.png differ diff --git a/3.7.0/_static/minus.png b/3.7.0/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/3.7.0/_static/minus.png differ diff --git a/3.7.0/_static/plus.png b/3.7.0/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/3.7.0/_static/plus.png differ diff --git a/3.7.0/_static/pygments.css b/3.7.0/_static/pygments.css new file mode 100644 index 000000000..d63846705 --- /dev/null +++ b/3.7.0/_static/pygments.css @@ -0,0 +1,258 @@ +.highlight pre { line-height: 125%; } +.highlight td.linenos .normal { color: #37474F; background-color: #263238; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos { color: #37474F; background-color: #263238; padding-left: 5px; padding-right: 5px; } +.highlight td.linenos .special { color: #607A86; background-color: #263238; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos.special { color: #607A86; background-color: #263238; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #2C3B41 } +.highlight { background: #263238; color: #EEFFFF } +.highlight .c { color: #546E7A; font-style: italic } /* Comment */ +.highlight .err { color: #FF5370 } /* Error */ +.highlight .esc { color: #89DDFF } /* Escape */ +.highlight .g { color: #EEFFFF } /* Generic */ +.highlight .k { color: #BB80B3 } /* Keyword */ +.highlight .l { color: #C3E88D } /* Literal */ +.highlight .n { color: #EEFFFF } /* Name */ +.highlight .o { color: #89DDFF } /* Operator */ +.highlight .p { color: #89DDFF } /* Punctuation */ +.highlight .ch { color: #546E7A; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #546E7A; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #546E7A; font-style: italic } /* Comment.Preproc */ +.highlight .cpf { color: #546E7A; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #546E7A; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #546E7A; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #FF5370 } /* Generic.Deleted */ +.highlight .ge { color: #89DDFF } /* Generic.Emph */ +.highlight .ges { color: #FFCB6B } /* Generic.EmphStrong */ +.highlight .gr { color: #FF5370 } /* Generic.Error */ +.highlight .gh { color: #C3E88D } /* Generic.Heading */ +.highlight .gi { color: #C3E88D } /* Generic.Inserted */ +.highlight .go { color: #546E7A } /* Generic.Output */ +.highlight .gp { color: #FFCB6B } /* Generic.Prompt */ +.highlight .gs { color: #FF5370 } /* Generic.Strong */ +.highlight .gu { color: #89DDFF } /* Generic.Subheading */ +.highlight .gt { color: #FF5370 } /* Generic.Traceback */ +.highlight .kc { color: #89DDFF } /* Keyword.Constant */ +.highlight .kd { color: #BB80B3 } /* Keyword.Declaration */ +.highlight .kn { color: #89DDFF; font-style: italic } /* Keyword.Namespace */ +.highlight .kp { color: #89DDFF } /* Keyword.Pseudo */ +.highlight .kr { color: #BB80B3 } /* Keyword.Reserved */ +.highlight .kt { color: #BB80B3 } /* Keyword.Type */ +.highlight .ld { color: #C3E88D } /* Literal.Date */ +.highlight .m { color: #F78C6C } /* Literal.Number */ +.highlight .s { color: #C3E88D } /* Literal.String */ +.highlight .na { color: #BB80B3 } /* Name.Attribute */ +.highlight .nb { color: #82AAFF } /* Name.Builtin */ +.highlight .nc { color: #FFCB6B } /* Name.Class */ +.highlight .no { color: #EEFFFF } /* Name.Constant */ +.highlight .nd { color: #82AAFF } /* Name.Decorator */ +.highlight .ni { color: #89DDFF } /* Name.Entity */ +.highlight .ne { color: #FFCB6B } /* Name.Exception */ +.highlight .nf { color: #82AAFF } /* Name.Function */ +.highlight .nl { color: #82AAFF } /* Name.Label */ +.highlight .nn { color: #FFCB6B } /* Name.Namespace */ +.highlight .nx { color: #EEFFFF } /* Name.Other */ +.highlight .py { color: #FFCB6B } /* Name.Property */ +.highlight .nt { color: #FF5370 } /* Name.Tag */ +.highlight .nv { color: #89DDFF } /* Name.Variable */ +.highlight .ow { color: #89DDFF; font-style: italic } /* Operator.Word */ +.highlight .pm { color: #89DDFF } /* Punctuation.Marker */ +.highlight .w { color: #EEFFFF } /* Text.Whitespace */ +.highlight .mb { color: #F78C6C } /* Literal.Number.Bin */ +.highlight .mf { color: #F78C6C } /* Literal.Number.Float */ +.highlight .mh { color: #F78C6C } /* Literal.Number.Hex */ +.highlight .mi { color: #F78C6C } /* Literal.Number.Integer */ +.highlight .mo { color: #F78C6C } /* Literal.Number.Oct */ +.highlight .sa { color: #BB80B3 } /* Literal.String.Affix */ +.highlight .sb { color: #C3E88D } /* Literal.String.Backtick */ +.highlight .sc { color: #C3E88D } /* Literal.String.Char */ +.highlight .dl { color: #EEFFFF } /* Literal.String.Delimiter */ +.highlight .sd { color: #546E7A; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #C3E88D } /* Literal.String.Double */ +.highlight .se { color: #EEFFFF } /* Literal.String.Escape */ +.highlight .sh { color: #C3E88D } /* Literal.String.Heredoc */ +.highlight .si { color: #89DDFF } /* Literal.String.Interpol */ +.highlight .sx { color: #C3E88D } /* Literal.String.Other */ +.highlight .sr { color: #89DDFF } /* Literal.String.Regex */ +.highlight .s1 { color: #C3E88D } /* Literal.String.Single */ +.highlight .ss { color: #89DDFF } /* Literal.String.Symbol */ +.highlight .bp { color: #89DDFF } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #82AAFF } /* Name.Function.Magic */ +.highlight .vc { color: #89DDFF } /* Name.Variable.Class */ +.highlight .vg { color: #89DDFF } /* Name.Variable.Global */ +.highlight .vi { color: #89DDFF } /* Name.Variable.Instance */ +.highlight .vm { color: #82AAFF } /* Name.Variable.Magic */ +.highlight .il { color: #F78C6C } /* Literal.Number.Integer.Long */ +@media not print { +body[data-theme="dark"] .highlight pre { line-height: 125%; } +body[data-theme="dark"] .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight .hll { background-color: #404040 } +body[data-theme="dark"] .highlight { background: #202020; color: #d0d0d0 } +body[data-theme="dark"] .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body[data-theme="dark"] .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body[data-theme="dark"] .highlight .esc { color: #d0d0d0 } /* Escape */ +body[data-theme="dark"] .highlight .g { color: #d0d0d0 } /* Generic */ +body[data-theme="dark"] .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body[data-theme="dark"] .highlight .l { color: #d0d0d0 } /* Literal */ +body[data-theme="dark"] .highlight .n { color: #d0d0d0 } /* Name */ +body[data-theme="dark"] .highlight .o { color: #d0d0d0 } /* Operator */ +body[data-theme="dark"] .highlight .x { color: #d0d0d0 } /* Other */ +body[data-theme="dark"] .highlight .p { color: #d0d0d0 } /* Punctuation */ +body[data-theme="dark"] .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body[data-theme="dark"] .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body[data-theme="dark"] .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body[data-theme="dark"] .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body[data-theme="dark"] .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body[data-theme="dark"] .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body[data-theme="dark"] .highlight .gd { color: #ff3a3a } /* Generic.Deleted */ +body[data-theme="dark"] .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body[data-theme="dark"] .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body[data-theme="dark"] .highlight .gr { color: #ff3a3a } /* Generic.Error */ +body[data-theme="dark"] .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +body[data-theme="dark"] .highlight .go { color: #cccccc } /* Generic.Output */ +body[data-theme="dark"] .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body[data-theme="dark"] .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body[data-theme="dark"] .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body[data-theme="dark"] .highlight .gt { color: #ff3a3a } /* Generic.Traceback */ +body[data-theme="dark"] .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body[data-theme="dark"] .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body[data-theme="dark"] .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body[data-theme="dark"] .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body[data-theme="dark"] .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body[data-theme="dark"] .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body[data-theme="dark"] .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body[data-theme="dark"] .highlight .m { color: #51b2fd } /* Literal.Number */ +body[data-theme="dark"] .highlight .s { color: #ed9d13 } /* Literal.String */ +body[data-theme="dark"] .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body[data-theme="dark"] .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body[data-theme="dark"] .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body[data-theme="dark"] .highlight .no { color: #40ffff } /* Name.Constant */ +body[data-theme="dark"] .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body[data-theme="dark"] .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body[data-theme="dark"] .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body[data-theme="dark"] .highlight .nf { color: #71adff } /* Name.Function */ +body[data-theme="dark"] .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body[data-theme="dark"] .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body[data-theme="dark"] .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body[data-theme="dark"] .highlight .py { color: #d0d0d0 } /* Name.Property */ +body[data-theme="dark"] .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body[data-theme="dark"] .highlight .nv { color: #40ffff } /* Name.Variable */ +body[data-theme="dark"] .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body[data-theme="dark"] .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body[data-theme="dark"] .highlight .w { color: #666666 } /* Text.Whitespace */ +body[data-theme="dark"] .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body[data-theme="dark"] .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body[data-theme="dark"] .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body[data-theme="dark"] .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body[data-theme="dark"] .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body[data-theme="dark"] .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body[data-theme="dark"] .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body[data-theme="dark"] .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body[data-theme="dark"] .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body[data-theme="dark"] .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body[data-theme="dark"] .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body[data-theme="dark"] .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body[data-theme="dark"] .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body[data-theme="dark"] .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body[data-theme="dark"] .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body[data-theme="dark"] .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body[data-theme="dark"] .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body[data-theme="dark"] .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body[data-theme="dark"] .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body[data-theme="dark"] .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body[data-theme="dark"] .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body[data-theme="dark"] .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body[data-theme="dark"] .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body[data-theme="dark"] .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body[data-theme="dark"] .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +@media (prefers-color-scheme: dark) { +body:not([data-theme="light"]) .highlight pre { line-height: 125%; } +body:not([data-theme="light"]) .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight .hll { background-color: #404040 } +body:not([data-theme="light"]) .highlight { background: #202020; color: #d0d0d0 } +body:not([data-theme="light"]) .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body:not([data-theme="light"]) .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body:not([data-theme="light"]) .highlight .esc { color: #d0d0d0 } /* Escape */ +body:not([data-theme="light"]) .highlight .g { color: #d0d0d0 } /* Generic */ +body:not([data-theme="light"]) .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body:not([data-theme="light"]) .highlight .l { color: #d0d0d0 } /* Literal */ +body:not([data-theme="light"]) .highlight .n { color: #d0d0d0 } /* Name */ +body:not([data-theme="light"]) .highlight .o { color: #d0d0d0 } /* Operator */ +body:not([data-theme="light"]) .highlight .x { color: #d0d0d0 } /* Other */ +body:not([data-theme="light"]) .highlight .p { color: #d0d0d0 } /* Punctuation */ +body:not([data-theme="light"]) .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body:not([data-theme="light"]) .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body:not([data-theme="light"]) .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body:not([data-theme="light"]) .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body:not([data-theme="light"]) .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body:not([data-theme="light"]) .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body:not([data-theme="light"]) .highlight .gd { color: #ff3a3a } /* Generic.Deleted */ +body:not([data-theme="light"]) .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body:not([data-theme="light"]) .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body:not([data-theme="light"]) .highlight .gr { color: #ff3a3a } /* Generic.Error */ +body:not([data-theme="light"]) .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */ +body:not([data-theme="light"]) .highlight .go { color: #cccccc } /* Generic.Output */ +body:not([data-theme="light"]) .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body:not([data-theme="light"]) .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body:not([data-theme="light"]) .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body:not([data-theme="light"]) .highlight .gt { color: #ff3a3a } /* Generic.Traceback */ +body:not([data-theme="light"]) .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body:not([data-theme="light"]) .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body:not([data-theme="light"]) .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body:not([data-theme="light"]) .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body:not([data-theme="light"]) .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body:not([data-theme="light"]) .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body:not([data-theme="light"]) .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body:not([data-theme="light"]) .highlight .m { color: #51b2fd } /* Literal.Number */ +body:not([data-theme="light"]) .highlight .s { color: #ed9d13 } /* Literal.String */ +body:not([data-theme="light"]) .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body:not([data-theme="light"]) .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body:not([data-theme="light"]) .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body:not([data-theme="light"]) .highlight .no { color: #40ffff } /* Name.Constant */ +body:not([data-theme="light"]) .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body:not([data-theme="light"]) .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body:not([data-theme="light"]) .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body:not([data-theme="light"]) .highlight .nf { color: #71adff } /* Name.Function */ +body:not([data-theme="light"]) .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body:not([data-theme="light"]) .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body:not([data-theme="light"]) .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body:not([data-theme="light"]) .highlight .py { color: #d0d0d0 } /* Name.Property */ +body:not([data-theme="light"]) .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body:not([data-theme="light"]) .highlight .nv { color: #40ffff } /* Name.Variable */ +body:not([data-theme="light"]) .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body:not([data-theme="light"]) .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body:not([data-theme="light"]) .highlight .w { color: #666666 } /* Text.Whitespace */ +body:not([data-theme="light"]) .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body:not([data-theme="light"]) .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body:not([data-theme="light"]) .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body:not([data-theme="light"]) .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body:not([data-theme="light"]) .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body:not([data-theme="light"]) .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body:not([data-theme="light"]) .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body:not([data-theme="light"]) .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body:not([data-theme="light"]) .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body:not([data-theme="light"]) .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body:not([data-theme="light"]) .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body:not([data-theme="light"]) .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body:not([data-theme="light"]) .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body:not([data-theme="light"]) .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body:not([data-theme="light"]) .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body:not([data-theme="light"]) .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body:not([data-theme="light"]) .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body:not([data-theme="light"]) .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body:not([data-theme="light"]) .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body:not([data-theme="light"]) .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body:not([data-theme="light"]) .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body:not([data-theme="light"]) .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body:not([data-theme="light"]) .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body:not([data-theme="light"]) .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body:not([data-theme="light"]) .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +} +} \ No newline at end of file diff --git a/3.7.0/_static/scripts/furo-extensions.js b/3.7.0/_static/scripts/furo-extensions.js new file mode 100644 index 000000000..e69de29bb diff --git a/3.7.0/_static/scripts/furo.js b/3.7.0/_static/scripts/furo.js new file mode 100644 index 000000000..0abb2afac --- /dev/null +++ b/3.7.0/_static/scripts/furo.js @@ -0,0 +1,3 @@ +/*! For license information please see furo.js.LICENSE.txt */ +(()=>{var t={856:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(856),e=n.n(t),o=null,r=null,c=document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;(function(t){const e=Math.floor(r.getBoundingClientRect().top);console.log(`headerTop: ${e}`),0==e&&t!=e?r.classList.add("scrolled"):r.classList.remove("scrolled")})(n=t),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+2.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})(); +//# sourceMappingURL=furo.js.map \ No newline at end of file diff --git a/3.7.0/_static/scripts/furo.js.LICENSE.txt b/3.7.0/_static/scripts/furo.js.LICENSE.txt new file mode 100644 index 000000000..1632189c7 --- /dev/null +++ b/3.7.0/_static/scripts/furo.js.LICENSE.txt @@ -0,0 +1,7 @@ +/*! + * gumshoejs v5.1.2 (patched by @pradyunsg) + * A simple, framework-agnostic scrollspy script. + * (c) 2019 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/gumshoe + */ diff --git a/3.7.0/_static/scripts/furo.js.map b/3.7.0/_static/scripts/furo.js.map new file mode 100644 index 000000000..80ea12b85 --- /dev/null +++ b/3.7.0/_static/scripts/furo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/furo.js","mappings":";iCAAA,MAQWA,SAWS,IAAX,EAAAC,EACH,EAAAA,EACkB,oBAAXC,OACLA,OACAC,KAbO,EAAF,WACP,OAaJ,SAAUD,GACR,aAMA,IAAIE,EAAW,CAEbC,SAAU,SACVC,aAAc,SAGdC,QAAQ,EACRC,YAAa,SAGbC,OAAQ,EACRC,QAAQ,EAGRC,QAAQ,GA6BNC,EAAY,SAAUC,EAAMC,EAAMC,GAEpC,GAAKA,EAAOC,SAASL,OAArB,CAGA,IAAIM,EAAQ,IAAIC,YAAYL,EAAM,CAChCM,SAAS,EACTC,YAAY,EACZL,OAAQA,IAIVD,EAAKO,cAAcJ,EAVgB,CAWrC,EAOIK,EAAe,SAAUR,GAC3B,IAAIS,EAAW,EACf,GAAIT,EAAKU,aACP,KAAOV,GACLS,GAAYT,EAAKW,UACjBX,EAAOA,EAAKU,aAGhB,OAAOD,GAAY,EAAIA,EAAW,CACpC,EAMIG,EAAe,SAAUC,GACvBA,GACFA,EAASC,MAAK,SAAUC,EAAOC,GAG7B,OAFcR,EAAaO,EAAME,SACnBT,EAAaQ,EAAMC,UACF,EACxB,CACT,GAEJ,EAwCIC,EAAW,SAAUlB,EAAME,EAAUiB,GACvC,IAAIC,EAASpB,EAAKqB,wBACd1B,EAnCU,SAAUO,GAExB,MAA+B,mBAApBA,EAASP,OACX2B,WAAWpB,EAASP,UAItB2B,WAAWpB,EAASP,OAC7B,CA2Be4B,CAAUrB,GACvB,OAAIiB,EAEAK,SAASJ,EAAOD,OAAQ,KACvB/B,EAAOqC,aAAeC,SAASC,gBAAgBC,cAG7CJ,SAASJ,EAAOS,IAAK,KAAOlC,CACrC,EAMImC,EAAa,WACf,OACEC,KAAKC,KAAK5C,EAAOqC,YAAcrC,EAAO6C,cAnCjCF,KAAKG,IACVR,SAASS,KAAKC,aACdV,SAASC,gBAAgBS,aACzBV,SAASS,KAAKE,aACdX,SAASC,gBAAgBU,aACzBX,SAASS,KAAKP,aACdF,SAASC,gBAAgBC,aAkC7B,EAmBIU,EAAY,SAAUzB,EAAUX,GAClC,IAAIqC,EAAO1B,EAASA,EAAS2B,OAAS,GACtC,GAbgB,SAAUC,EAAMvC,GAChC,SAAI4B,MAAgBZ,EAASuB,EAAKxB,QAASf,GAAU,GAEvD,CAUMwC,CAAYH,EAAMrC,GAAW,OAAOqC,EACxC,IAAK,IAAII,EAAI9B,EAAS2B,OAAS,EAAGG,GAAK,EAAGA,IACxC,GAAIzB,EAASL,EAAS8B,GAAG1B,QAASf,GAAW,OAAOW,EAAS8B,EAEjE,EAOIC,EAAmB,SAAUC,EAAK3C,GAEpC,GAAKA,EAAST,QAAWoD,EAAIC,WAA7B,CAGA,IAAIC,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASR,aAG7BkD,EAAiBG,EAAI7C,GAV0B,CAWjD,EAOIiD,EAAa,SAAUC,EAAOlD,GAEhC,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASX,UAC7B6D,EAAMnC,QAAQgC,UAAUC,OAAOhD,EAASV,cAGxCoD,EAAiBG,EAAI7C,GAGrBJ,EAAU,oBAAqBiD,EAAI,CACjCM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,EAOIoD,EAAiB,SAAUT,EAAK3C,GAElC,GAAKA,EAAST,OAAd,CAGA,IAAIsD,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASR,aAG1B4D,EAAeP,EAAI7C,GAVS,CAW9B,EA6LA,OA1JkB,SAAUsD,EAAUC,GAKpC,IACIC,EAAU7C,EAAU8C,EAASC,EAAS1D,EADtC2D,EAAa,CAUjBA,MAAmB,WAEjBH,EAAWhC,SAASoC,iBAAiBN,GAGrC3C,EAAW,GAGXkD,MAAMC,UAAUC,QAAQC,KAAKR,GAAU,SAAUjB,GAE/C,IAAIxB,EAAUS,SAASyC,eACrBC,mBAAmB3B,EAAK4B,KAAKC,OAAO,KAEjCrD,GAGLJ,EAAS0D,KAAK,CACZ1B,IAAKJ,EACLxB,QAASA,GAEb,IAGAL,EAAaC,EACf,EAKAgD,OAAoB,WAElB,IAAIW,EAASlC,EAAUzB,EAAUX,GAG5BsE,EASDb,GAAWa,EAAOvD,UAAY0C,EAAQ1C,UAG1CkC,EAAWQ,EAASzD,GAzFT,SAAUkD,EAAOlD,GAE9B,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASX,UAC1B6D,EAAMnC,QAAQgC,UAAUM,IAAIrD,EAASV,cAGrC8D,EAAeP,EAAI7C,GAGnBJ,EAAU,kBAAmBiD,EAAI,CAC/BM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,CAqEIuE,CAASD,EAAQtE,GAGjByD,EAAUa,GAfJb,IACFR,EAAWQ,EAASzD,GACpByD,EAAU,KAchB,GAMIe,EAAgB,SAAUvE,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,sBAAsBf,EAAWgB,OACpD,EAMIC,EAAgB,SAAU3E,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,uBAAsB,WACrChE,EAAaC,GACbgD,EAAWgB,QACb,GACF,EAkDA,OA7CAhB,EAAWkB,QAAU,WAEfpB,GACFR,EAAWQ,EAASzD,GAItBd,EAAO4F,oBAAoB,SAAUN,GAAe,GAChDxE,EAASN,QACXR,EAAO4F,oBAAoB,SAAUF,GAAe,GAItDjE,EAAW,KACX6C,EAAW,KACXC,EAAU,KACVC,EAAU,KACV1D,EAAW,IACb,EAOEA,EA3XS,WACX,IAAI+E,EAAS,CAAC,EAOd,OANAlB,MAAMC,UAAUC,QAAQC,KAAKgB,WAAW,SAAUC,GAChD,IAAK,IAAIC,KAAOD,EAAK,CACnB,IAAKA,EAAIE,eAAeD,GAAM,OAC9BH,EAAOG,GAAOD,EAAIC,EACpB,CACF,IACOH,CACT,CAkXeK,CAAOhG,EAAUmE,GAAW,CAAC,GAGxCI,EAAW0B,QAGX1B,EAAWgB,SAGXzF,EAAOoG,iBAAiB,SAAUd,GAAe,GAC7CxE,EAASN,QACXR,EAAOoG,iBAAiB,SAAUV,GAAe,GAS9CjB,CACT,CAOF,CArcW4B,CAAQvG,EAChB,UAFM,SAEN,uBCXDwG,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,CAAC,GAOX,OAHAE,EAAoBL,GAAU1B,KAAK8B,EAAOD,QAASC,EAAQA,EAAOD,QAASJ,GAGpEK,EAAOD,OACf,CCrBAJ,EAAoBO,EAAKF,IACxB,IAAIG,EAASH,GAAUA,EAAOI,WAC7B,IAAOJ,EAAiB,QACxB,IAAM,EAEP,OADAL,EAAoBU,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,CAAM,ECLdR,EAAoBU,EAAI,CAACN,EAASQ,KACjC,IAAI,IAAInB,KAAOmB,EACXZ,EAAoBa,EAAED,EAAYnB,KAASO,EAAoBa,EAAET,EAASX,IAC5EqB,OAAOC,eAAeX,EAASX,EAAK,CAAEuB,YAAY,EAAMC,IAAKL,EAAWnB,IAE1E,ECNDO,EAAoBxG,EAAI,WACvB,GAA0B,iBAAf0H,WAAyB,OAAOA,WAC3C,IACC,OAAOxH,MAAQ,IAAIyH,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAX3H,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCAxBuG,EAAoBa,EAAI,CAACrB,EAAK6B,IAAUP,OAAOzC,UAAUqB,eAAenB,KAAKiB,EAAK6B,4CCK9EC,EAAY,KACZC,EAAS,KACTC,EAAgBzF,SAASC,gBAAgByF,UAC7C,MAAMC,EAAmB,GA8EzB,SAASC,IACP,MAAMC,EAAeC,aAAaC,QAAQ,UAAY,OAZxD,IAAkBC,EACH,WADGA,EAaItI,OAAOuI,WAAW,gCAAgCC,QAI/C,SAAjBL,EACO,QACgB,SAAhBA,EACA,OAEA,OAIU,SAAjBA,EACO,OACgB,QAAhBA,EACA,QAEA,SA9BoB,SAATG,GAA4B,SAATA,IACzCG,QAAQC,MAAM,2BAA2BJ,yBACzCA,EAAO,QAGThG,SAASS,KAAK4F,QAAQC,MAAQN,EAC9BF,aAAaS,QAAQ,QAASP,GAC9BG,QAAQK,IAAI,cAAcR,UA0B5B,CAkDA,SAASnC,KART,WAEE,MAAM4C,EAAUzG,SAAS0G,uBAAuB,gBAChDrE,MAAMsE,KAAKF,GAASlE,SAASqE,IAC3BA,EAAI9C,iBAAiB,QAAS8B,EAAe,GAEjD,CAGEiB,GA9CF,WAEE,IAAIC,EAA6B,EAC7BC,GAAU,EAEdrJ,OAAOoG,iBAAiB,UAAU,SAAUuB,GAC1CyB,EAA6BpJ,OAAOsJ,QAE/BD,IACHrJ,OAAOwF,uBAAsB,WAzDnC,IAAuB+D,GAxDvB,SAAgCA,GAC9B,MAAMC,EAAY7G,KAAK8G,MAAM3B,EAAO7F,wBAAwBQ,KAE5DgG,QAAQK,IAAI,cAAcU,KACT,GAAbA,GAAkBD,GAAaC,EACjC1B,EAAOjE,UAAUM,IAAI,YAErB2D,EAAOjE,UAAUC,OAAO,WAE5B,EAgDE4F,CADqBH,EA0DDH,GAvGtB,SAAmCG,GAC7BA,EAAYtB,EACd3F,SAASC,gBAAgBsB,UAAUC,OAAO,oBAEtCyF,EAAYxB,EACdzF,SAASC,gBAAgBsB,UAAUM,IAAI,oBAC9BoF,EAAYxB,GACrBzF,SAASC,gBAAgBsB,UAAUC,OAAO,oBAG9CiE,EAAgBwB,CAClB,CAoCEI,CAA0BJ,GAlC5B,SAA6BA,GACT,OAAd1B,IAKa,GAAb0B,EACF1B,EAAU+B,SAAS,EAAG,GAGtBjH,KAAKC,KAAK2G,IACV5G,KAAK8G,MAAMnH,SAASC,gBAAgBS,aAAehD,OAAOqC,aAE1DwF,EAAU+B,SAAS,EAAG/B,EAAU7E,cAGhBV,SAASuH,cAAc,mBAc3C,CAKEC,CAAoBP,GAwDdF,GAAU,CACZ,IAEAA,GAAU,EAEd,IACArJ,OAAO+J,QACT,CA6BEC,GA1BkB,OAAdnC,GAKJ,IAAI,IAAJ,CAAY,cAAe,CACzBrH,QAAQ,EACRyJ,WAAW,EACX9J,SAAU,iBACVI,OAAQ,KACN,IAAI2J,EAAMhI,WAAWiI,iBAAiB7H,SAASC,iBAAiB6H,UAChE,OAAOtC,EAAO7F,wBAAwBoI,OAAS,IAAMH,EAAM,CAAC,GAiBlE,CAcA5H,SAAS8D,iBAAiB,oBAT1B,WACE9D,SAASS,KAAKW,WAAWG,UAAUC,OAAO,SAE1CgE,EAASxF,SAASuH,cAAc,UAChChC,EAAYvF,SAASuH,cAAc,eAEnC1D,GACF","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader(positionY) {\n const headerTop = Math.floor(header.getBoundingClientRect().top);\n\n console.log(`headerTop: ${headerTop}`);\n if (headerTop == 0 && positionY != headerTop) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader(positionY);\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 2.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","GO_TO_TOP_OFFSET","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","headerTop","floor","scrollHandlerForHeader","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""} \ No newline at end of file diff --git a/3.7.0/_static/searchtools.js b/3.7.0/_static/searchtools.js new file mode 100644 index 000000000..b08d58c9b --- /dev/null +++ b/3.7.0/_static/searchtools.js @@ -0,0 +1,620 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlink", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + const score = Math.round(Scorer.title * queryLower.length / title.length); + const boost = titles[file] === title ? 1 : 0; // add a boost for document titles + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score + boost, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/3.7.0/_static/skeleton.css b/3.7.0/_static/skeleton.css new file mode 100644 index 000000000..467c878c6 --- /dev/null +++ b/3.7.0/_static/skeleton.css @@ -0,0 +1,296 @@ +/* Some sane resets. */ +html { + height: 100%; +} + +body { + margin: 0; + min-height: 100%; +} + +/* All the flexbox magic! */ +body, +.sb-announcement, +.sb-content, +.sb-main, +.sb-container, +.sb-container__inner, +.sb-article-container, +.sb-footer-content, +.sb-header, +.sb-header-secondary, +.sb-footer { + display: flex; +} + +/* These order things vertically */ +body, +.sb-main, +.sb-article-container { + flex-direction: column; +} + +/* Put elements in the center */ +.sb-header, +.sb-header-secondary, +.sb-container, +.sb-content, +.sb-footer, +.sb-footer-content { + justify-content: center; +} +/* Put elements at the ends */ +.sb-article-container { + justify-content: space-between; +} + +/* These elements grow. */ +.sb-main, +.sb-content, +.sb-container, +article { + flex-grow: 1; +} + +/* Because padding making this wider is not fun */ +article { + box-sizing: border-box; +} + +/* The announcements element should never be wider than the page. */ +.sb-announcement { + max-width: 100%; +} + +.sb-sidebar-primary, +.sb-sidebar-secondary { + flex-shrink: 0; + width: 17rem; +} + +.sb-announcement__inner { + justify-content: center; + + box-sizing: border-box; + height: 3rem; + + overflow-x: auto; + white-space: nowrap; +} + +/* Sidebars, with checkbox-based toggle */ +.sb-sidebar-primary, +.sb-sidebar-secondary { + position: fixed; + height: 100%; + top: 0; +} + +.sb-sidebar-primary { + left: -17rem; + transition: left 250ms ease-in-out; +} +.sb-sidebar-secondary { + right: -17rem; + transition: right 250ms ease-in-out; +} + +.sb-sidebar-toggle { + display: none; +} +.sb-sidebar-overlay { + position: fixed; + top: 0; + width: 0; + height: 0; + + transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; + + opacity: 0; + background-color: rgba(0, 0, 0, 0.54); +} + +#sb-sidebar-toggle--primary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], +#sb-sidebar-toggle--secondary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { + width: 100%; + height: 100%; + opacity: 1; + transition: width 0ms ease, height 0ms ease, opacity 250ms ease; +} + +#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { + left: 0; +} +#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { + right: 0; +} + +/* Full-width mode */ +.drop-secondary-sidebar-for-full-width-content + .hide-when-secondary-sidebar-shown { + display: none !important; +} +.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { + display: none !important; +} + +/* Mobile views */ +.sb-page-width { + width: 100%; +} + +.sb-article-container, +.sb-footer-content__inner, +.drop-secondary-sidebar-for-full-width-content .sb-article, +.drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 100vw; +} + +.sb-article, +.match-content-width { + padding: 0 1rem; + box-sizing: border-box; +} + +@media (min-width: 32rem) { + .sb-article, + .match-content-width { + padding: 0 2rem; + } +} + +/* Tablet views */ +@media (min-width: 42rem) { + .sb-article-container { + width: auto; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 42rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 46rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 46rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 50rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 50rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Tablet views */ +@media (min-width: 59rem) { + .sb-sidebar-secondary { + position: static; + } + .hide-when-secondary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 63rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 67rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Desktop views */ +@media (min-width: 76rem) { + .sb-sidebar-primary { + position: static; + } + .hide-when-primary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} + +/* Full desktop views */ +@media (min-width: 80rem) { + .sb-article, + .match-content-width { + width: 46rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } +} + +@media (min-width: 84rem) { + .sb-article, + .match-content-width { + width: 50rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } +} + +@media (min-width: 88rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-page-width { + width: 88rem; + } +} diff --git a/3.7.0/_static/sphinx_highlight.js b/3.7.0/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/3.7.0/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/3.7.0/_static/styles/furo-extensions.css b/3.7.0/_static/styles/furo-extensions.css new file mode 100644 index 000000000..822958761 --- /dev/null +++ b/3.7.0/_static/styles/furo-extensions.css @@ -0,0 +1,2 @@ +#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} +/*# sourceMappingURL=furo-extensions.css.map*/ \ No newline at end of file diff --git a/3.7.0/_static/styles/furo-extensions.css.map b/3.7.0/_static/styles/furo-extensions.css.map new file mode 100644 index 000000000..c26eac7f5 --- /dev/null +++ b/3.7.0/_static/styles/furo-extensions.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAEE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cAIA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UCzCN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/3.7.0/_static/styles/furo.css b/3.7.0/_static/styles/furo.css new file mode 100644 index 000000000..05a56b17f --- /dev/null +++ b/3.7.0/_static/styles/furo.css @@ -0,0 +1,2 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,p,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;clip:rect(0,0,0,0)!important;background:var(--color-background-primary);border:0!important;color:var(--color-foreground-primary);white-space:nowrap!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-stack--headings:var(--font-stack);--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8,');--icon-pencil:url('data:image/svg+xml;charset=utf-8,');--icon-abstract:url('data:image/svg+xml;charset=utf-8,');--icon-info:url('data:image/svg+xml;charset=utf-8,');--icon-flame:url('data:image/svg+xml;charset=utf-8,');--icon-question:url('data:image/svg+xml;charset=utf-8,');--icon-warning:url('data:image/svg+xml;charset=utf-8,');--icon-failure:url('data:image/svg+xml;charset=utf-8,');--icon-spark:url('data:image/svg+xml;charset=utf-8,');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#6b6f76;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#0a4bff;--color-brand-content:#2757dd;--color-brand-visited:#872ee0;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-api-added:#21632c;--color-api-added-border:#38a84d;--color-api-changed:#046172;--color-api-changed-border:#06a1bc;--color-api-deprecated:#605706;--color-api-deprecated-border:#f0d90f;--color-api-removed:#b30000;--color-api-removed-border:#ff5c5c;--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link--hover:var(--color-brand-content);--color-link-underline--hover:var(--color-foreground-border);--color-link--visited:var(--color-brand-visited);--color-link-underline--visited:var(--color-background-border);--color-link--visited--hover:var(--color-brand-visited);--color-link-underline--visited--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:block}@media(prefers-color-scheme:dark){body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-dark{display:block}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:none}}body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-family:var(--font-stack--headings);font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}a:visited{color:var(--color-link--visited);text-decoration-color:var(--color-link-underline--visited)}a:visited:hover{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}a:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link:hover:visited{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{height:100%}.skip-to-content,body,html{background:var(--color-background-primary);color:var(--color-foreground-primary)}.skip-to-content{border-radius:1rem;left:.25rem;padding:1rem;position:fixed;top:.25rem;transform:translateY(-200%);transition:transform .3s ease-in-out;z-index:40}.skip-to-content:focus-within{transform:translateY(0)}article{background:var(--color-content-background);color:var(--color-content-foreground);overflow-wrap:break-word}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{display:flex}.theme-toggle{background:transparent;border:none;cursor:pointer;display:flex;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1.25rem;width:1.25rem}.theme-toggle-header{align-items:center;display:flex;justify-content:center}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1.5rem;width:1.5rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg,.content-icon-container .view-this-page svg{color:inherit;height:1.25rem;width:1.25rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{height:1rem;width:1rem;fill:currentColor;display:inline-block}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.content{margin-left:auto;margin-right:auto;padding:0 1em}}@media(max-width:63em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.theme-toggle-header,.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.5rem;width:1.5rem}:target{scroll-margin-top:calc(var(--header-height) + 2.5rem)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}}@media(max-width:48em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){article[role=main] aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}.admonition p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}.admonition p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:4.25rem}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}div.deprecated,div.versionadded,div.versionchanged,div.versionremoved{border-left:.1875rem solid;border-radius:.125rem;padding-left:.75rem}div.deprecated p,div.versionadded p,div.versionchanged p,div.versionremoved p{margin-bottom:.125rem;margin-top:.125rem}div.versionadded{border-color:var(--color-api-added-border)}div.versionadded .versionmodified{color:var(--color-api-added)}div.versionchanged{border-color:var(--color-api-changed-border)}div.versionchanged .versionmodified{color:var(--color-api-changed)}div.deprecated{border-color:var(--color-api-deprecated-border)}div.deprecated .versionmodified{color:var(--color-api-deprecated)}div.versionremoved{border-color:var(--color-api-removed-border)}div.versionremoved .versionmodified{color:var(--color-api-removed)}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);padding:.1em .2em}pre.literal-block .sig-inline,pre.literal-block code.literal{font-size:inherit;padding:0}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>:not(span),div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}[role=main] .table-wrapper.container{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:2.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(2.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(2.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover);color:var(--color-sidebar-link-text)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23607D8B' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath stroke='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree a.reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling. Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right} +/*# sourceMappingURL=furo.css.map*/ \ No newline at end of file diff --git a/3.7.0/_static/styles/furo.css.map b/3.7.0/_static/styles/furo.css.map new file mode 100644 index 000000000..3ecc37150 --- /dev/null +++ b/3.7.0/_static/styles/furo.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo.css","mappings":"AAAA,2EAA2E,CAU3E,KACE,gBAAiB,CACjB,6BACF,CASA,KACE,QACF,CAMA,KACE,aACF,CAOA,GACE,aAAc,CACd,cACF,CAUA,GACE,sBAAuB,CACvB,QAAS,CACT,gBACF,CAOA,IACE,+BAAiC,CACjC,aACF,CASA,EACE,4BACF,CAOA,YACE,kBAAmB,CACnB,yBAA0B,CAC1B,gCACF,CAMA,SAEE,kBACF,CAOA,cAGE,+BAAiC,CACjC,aACF,CAeA,QAEE,aAAc,CACd,aAAc,CACd,iBAAkB,CAClB,uBACF,CAEA,IACE,aACF,CAEA,IACE,SACF,CASA,IACE,iBACF,CAUA,sCAKE,mBAAoB,CACpB,cAAe,CACf,gBAAiB,CACjB,QACF,CAOA,aAEE,gBACF,CAOA,cAEE,mBACF,CAMA,gDAIE,yBACF,CAMA,wHAIE,iBAAkB,CAClB,SACF,CAMA,4GAIE,6BACF,CAMA,SACE,0BACF,CASA,OACE,qBAAsB,CACtB,aAAc,CACd,aAAc,CACd,cAAe,CACf,SAAU,CACV,kBACF,CAMA,SACE,uBACF,CAMA,SACE,aACF,CAOA,6BAEE,qBAAsB,CACtB,SACF,CAMA,kFAEE,WACF,CAOA,cACE,4BAA6B,CAC7B,mBACF,CAMA,yCACE,uBACF,CAOA,6BACE,yBAA0B,CAC1B,YACF,CASA,QACE,aACF,CAMA,QACE,iBACF,CAiBA,kBACE,YACF,CCvVA,aAcE,kEACE,uBAOF,WACE,iDAMF,kCACE,wBAEF,qCAEE,uBADA,uBACA,CAEF,SACE,wBAtBA,CCpBJ,iBAGE,qBAEA,sBACA,0BAFA,oBAHA,4BACA,oBAKA,6BAIA,2CAFA,mBACA,sCAFA,4BAGA,CAEF,gBACE,aCTF,KCGE,mHAEA,wGAEA,wCAAyC,CAEzC,wBAAyB,CACzB,wBAAyB,CACzB,4BAA6B,CAC7B,yBAA0B,CAC1B,2BAA4B,CAG5B,sDAAuD,CACvD,gDAAiD,CACjD,wDAAyD,CAGzD,0CAA2C,CAC3C,gDAAiD,CACjD,gDAAiD,CAKjD,gCAAiC,CACjC,sCAAuC,CAGvC,2CAA4C,CAG5C,uCAAwC,CCjCxC,+FAGA,uBAAwB,CAGxB,iCAAkC,CAClC,kCAAmC,CAEnC,+BAAgC,CAChC,sCAAuC,CACvC,sCAAuC,CACvC,qGAIA,mDAAoD,CAEpD,mCAAoC,CACpC,8CAA+C,CAC/C,gDAAiD,CACjD,kCAAmC,CACnC,6DAA8D,CAG9D,6BAA8B,CAC9B,6BAA8B,CAC9B,+BAAgC,CAChC,kCAAmC,CACnC,kCAAmC,CCPjC,+jBCYA,iqCAZF,iaCVA,8KAOA,4SAWA,4SAUA,0CACA,gEAGA,0CAGA,gEAGA,yCACA,+DAIA,4CACA,kEAGA,wCAUA,8DACA,uCAGA,4DACA,sCACA,2DAGA,4CACA,kEACA,uCAGA,6DACA,2GAGA,sHAEA,yFAEA,+CACA,+EAGA,4MAOA,gCACA,sHAIA,kCACA,uEACA,gEACA,4DACA,kEAGA,2DACA,sDACA,0CACA,8CACA,wGAGA,0BACA,iCAGA,+DACA,+BACA,sCACA,+DAEA,kGACA,oCACA,yDACA,sCL7HF,kCAEA,sDAIA,0CK2HE,kEAIA,oDACA,sDAGA,oCACA,oEAEA,0DACA,qDAIA,oDACA,6DAIA,iEAIA,2DAIA,2DAGA,4DACA,gEAIA,gEAEA,gFAEA,oNASA,qDLxKE,gFAGE,4DAIF,oEKkHF,yEAEA,6DAGA,0DAEA,uDACA,qDACA,wDAIA,6DAIA,yDACA,2DAIA,uCAGA,wCACA,sDAGA,+CAGA,6DAEA,iDACA,+DAEA,wDAEA,sEAMA,0DACA,sBACA,mEL9JI,wEAEA,iCACE,+BAMN,wEAGA,iCACE,kFAEA,uEAIF,gEACE,8BAGF,qEMvDA,sCAKA,wFAKA,iCAIA,0BAWA,iCACA,4BACA,mCAGA,+BAEA,sCACA,4BAEA,mCAEA,sCAKA,sDAIA,gCAEA,gEAQF,wCAME,sBACA,kCAKA,uBAEA,gEAIA,2BAIA,mCAEA,qCACA,iCAGE,+BACA,wEAEE,iCACA,kFAGF,6BACA,0CACF,kCAEE,8BACE,8BACA,qEAEE,sCACA,wFCnFN,iCAGF,2DAEE,4BACA,oCAGA,mIAGA,4HACE,gEAMJ,+CAGE,sBACA,yCAEF,uBAEE,sEAKA,gDACA,kEAGA,iFAGE,YAGF,EACA,4HAQF,mBACE,6BACA,mBACA,wCACA,wCACA,2CAIA,eAGA,mBAKE,mBAGA,CAJA,uCACA,iBAFF,gBACE,CAKE,mBACA,mBAGJ,oBAIF,+BAGE,kDACA,OADA,kBAGA,CAFA,gBAEA,mBACA,oBAEA,sCACA,OAGF,cAHE,WAGF,GAEE,oBACA,CAHF,gBAGE,CC9Gc,YDiHd,+CAIF,SAEE,CAPF,UACE,wBAMA,4BAEA,GAGA,uBACA,CAJA,yBAGA,CACA,iDAKA,2CAGA,2DAQA,iBACA,uCAGA,kEAKE,SAKJ,8BACE,yDACA,2BAEA,oBACA,8BAEA,yDAEE,4BAEJ,uCACE,CACA,iEAGA,CAEA,wCACE,uBACA,kDAEA,0DAEE,CAJF,oBAIE,0GAWN,aACE,CAHA,YAGA,4HASA,+CAGF,sBACE,WACA,WAQA,4BAFF,0CAEE,CARA,qCAsBA,CAdA,iBAEA,kBACE,aADF,4BACE,WAMF,2BAGF,qCAEE,CAXE,UAWF,+BAGA,uBAEA,SAEA,0CAIE,CANF,qCAEA,CAIE,2DACE,gBAIN,+CAIA,CAEA,kDAKE,CAPF,8BAEA,CAOE,YACA,CAjBI,2BAGN,CAHM,WAcJ,UAGA,CAEA,2GAIF,iCAGE,8BAIA,qBACA,oBACF,uBAOI,0CAIA,CATF,6DAKE,CALF,sBASE,qCAKF,CACE,cACA,CAFF,sBAEE,CACA,+BAEA,qBAEE,WAKN,aACE,sCAGA,mBAEA,6BAMA,kCACA,CAJA,sBACA,aAEA,CAJA,eACA,MAIA,2FAEA,UAGA,YACA,sBACE,8BAEA,CALF,aACA,WAIE,OACA,oBAEF,uBACE,WAEF,YAFE,UAEF,eAgBA,kBACE,CAhBA,qDAQF,qCAGF,CAGI,YACF,CAJF,2BAGI,CAEA,eACA,qBAGA,mEAEA,qBACA,8BAIA,kBADF,kBACE,yBAEJ,oCAGI,qDAIJ,+BAGI,oCAEA,+CAQF,4CACE,yBACF,2BAOE,sBACA,CAHA,WACA,CAFF,cACE,CAJA,YAGF,CAEE,SAEA,mBAGA,kDAEE,CAJF,cAEA,cAEE,sBAEA,mBADA,YACA,uBACA,mDACE,CADF,YACE,iDAEA,uCAEN,+DAOE,mBADF,sBACE,mBAGF,aACE,sCAIA,aADF,WACE,CAKF,SACE,CAHJ,kBAEE,CAJE,gBAEJ,CAHI,iBAMA,yFAKA,aACA,eACA,cElbJ,iBAEE,aADA,iBACA,6BAEA,kCAEA,SACA,UAIA,gCACA,CALA,SAEA,SAEA,CAJA,0EAEA,CAFA,OAKA,CAGA,mDACE,iBAGF,gCACE,CADF,UACE,aAEJ,iCAEE,CAFF,UAEE,wCAEA,WACA,WADA,UACA,CACA,4CAGA,MACA,CADA,KACA,wCACA,UAGA,CAJA,UAIA,6DAUA,0CACE,CAFF,mBAEE,wEACA,CAVA,YACA,CAMF,mBAJE,OAOA,gBAJJ,gCACE,CANE,cACA,CAHA,oBACA,CAGA,QAGJ,CAII,0BACA,CADA,UACA,wCAEJ,kBACE,0DACA,gCACE,kBACA,CADA,YACA,oEACA,2CAMF,mDAII,CALN,YACE,CANE,cAKJ,CACE,iBAII,kEACA,yCACE,kDACA,yDACE,+CACA,uBANN,CAMM,+BANN,uCACE,qDACA,4BAEE,mBADA,0CACA,CADA,qBACA,0DACE,wCACA,sGALJ,oCACA,sBACE,kBAFF,UAEE,2CACA,wFACE,cACA,kEANN,uBACE,iDACA,CADA,UACA,0DACE,wDAEE,iEACA,qEANN,sCACE,CAGE,iBAHF,gBAGE,qBACE,CAJJ,uBACA,gDACE,wDACA,6DAHF,2CACA,CADA,gBACA,eACE,CAGE,sBANN,8BACE,CAII,iBAFF,4DACA,WACE,YADF,uCACE,6EACA,2BANN,8CACE,kDACA,0CACE,8BACA,yFACE,sBACA,sFALJ,mEACA,sBACE,kEACA,6EACE,uCACA,kEALJ,qGAEE,kEACA,6EACE,uCACA,kEALJ,8CACA,uDACE,sEACA,2EACE,sCACA,iEALJ,mGACA,qCACE,oDACA,0DACE,6GACA,gDAGR,yDCrEA,sEACE,CACA,6GACE,gEACF,iGAIF,wFACE,qDAGA,mGAEE,2CAEF,4FACE,gCACF,wGACE,8DAEE,6FAIA,iJAKN,6GACE,gDAKF,yDACA,qCAGA,6BACA,kBACA,qDAKA,oCAEA,+DAGA,2CAGE,oDAIA,oEAEE,qBAGJ,wDAEE,uCAEF,kEAGA,8CAEA,uDAIF,gEAIE,6BACA,gEAIA,+CACE,0EAIF,sDAEE,+DAGF,sCACA,8BACE,oCAEJ,wBACE,4FAEE,gBAEJ,yGAGI,kBAGJ,CCnHE,2MCFF,oBAGE,wGAKA,iCACE,CADF,wBACE,8GAQA,mBCjBJ,2GAIE,mBACA,6HAMA,YACE,mIAYF,eACA,CAHF,YAGE,4FAGE,8BAKF,uBAkBE,sCACA,CADA,qBAbA,wCAIA,CALF,8BACE,CADF,gBAKE,wCACA,CAOA,kDACA,CACA,kCAKF,6BAGA,4CACE,kDACA,eAGF,cACE,aACA,iBACA,yBACA,8BACA,WAGJ,2BACE,cAGA,+BACA,CAHA,eAGA,wCACA,YACA,iBACA,uEAGA,0BACA,2CAEA,8EAGI,qBACA,CAFF,kBAEE,kBAGN,0CAGE,mCAGA,4BAIA,gEACE,qCACA,8BAEA,gBACA,+CACA,iCAEF,iCAEE,gEACA,qCAGF,8BAEE,+BAIA,yCAEE,qBADA,gBACA,yBAKF,eACA,CAFF,YACE,CACA,iBACA,qDAEA,mDCvIJ,2FAOE,iCACA,CAEA,eACA,CAHA,kBAEA,CAFA,wBAGA,8BACA,eACE,CAFF,YAEE,0BACA,8CAGA,oBACE,oCAGA,kBACE,8DAEA,iBAEN,UACE,8BAIJ,+CAEE,qDAEF,kDAIE,YAEF,CAFE,YAEF,CCpCE,mFADA,kBAKE,CAJF,IAGA,aACE,mCAGA,iDACE,+BAEJ,wBAEE,mBAMA,6CAEF,CAJE,mBAEA,CAEF,kCAGE,CARF,kBACE,CAHA,eAUA,YACA,mBACA,CADA,UACA,wCC9BF,oBDkCE,wBCnCJ,uCACE,+BACA,+DACA,sBAGA,qBCDA,6CAIE,CAPF,uBAGA,CDGE,oBACF,yDAEE,CCDE,2CAGF,CAJA,kCACE,CDJJ,YACE,CAIA,eCTF,CDKE,uBCMA,gCACE,YAEF,oCAEE,wBACA,0BAIF,iBAEA,cADF,UACE,uBAEA,iCAEA,wCAEA,6CAMA,CAYF,gCATI,4BASJ,CAZE,mCAEE,iCAUJ,4BAGE,4DADA,+BACA,CAHF,qBAGE,sCACE,OAEF,iBAHA,SAGA,iHACE,2DAKF,CANA,8EAMA,uSAEE,kBAEF,+FACE,yCCjEJ,WACA,yBAGA,uBACA,gBAEA,uCAIA,CAJA,iCAIA,uCAGA,UACE,gBACA,qBAEA,0CClBJ,gBACE,KAGF,qBACE,YAGF,CAHE,cAGF,gCAEE,mBACA,iEAEA,oCACA,wCAEA,sBACA,WAEA,CAFA,YAEA,8EAEA,mCAFA,iBAEA,6BAIA,wEAKA,sDAIE,CARF,mDAIA,CAIE,cAEF,8CAIA,oBAFE,iBAEF,8CAGE,eAEF,CAFE,YAEF,OAEE,kBAGJ,CAJI,eACA,CAFF,mBAKF,yCCjDE,oBACA,CAFA,iBAEA,uCAKE,iBACA,qCAGA,mBCZJ,CDWI,gBCXJ,6BAEE,eACA,sBAGA,eAEA,sBACA,oDACA,iGAMA,gBAFE,YAEF,8FAME,iJCnBF,YACA,gNAWE,gDAEF,iSAaE,kBACE,gHAKF,oCACE,eACF,CADE,UACF,8CACE,gDACF,wCACE,oBCxCJ,oBAEF,6BACE,QACE,kDAGF,yBACE,kDAmBA,kDAEF,CAhBA,+CAaA,CAbA,oBAaA,0FACE,CADF,gGAfF,cACE,gBACA,CAaA,0BAGA,mQACE,gBAGF,oMACE,iBACA,CAFF,eACE,CADF,gBAEE,aAGJ,iCAEE,CAFF,wCAEE,wBAUE,+VAIE,uEAHA,2BAGA,wXAKJ,iDAGF,CARM,+CACE,iDAIN,CALI,gBAQN,mHACE,gBAGF,2DACE,0EAOA,0EAGF,gBAEE,6DC/EA,kDACA,gCACA,qDAGA,qBACA,qDCFA,cACA,eAEA,yBAGF,sBAEE,iBACA,sNAWA,iBACE,kBACA,wRAgBA,kBAEA,iOAgBA,uCACE,uEAEA,kBAEF,qUAuBE,iDAIJ,CACA,geCxFF,4BAEE,CAQA,6JACA,iDAIA,sEAGA,mDAOF,iDAGE,4DAIA,8CACA,qDAEE,eAFF,cAEE,oBAEF,uBAFE,kCAGA,eACA,iBACA,mBAIA,mDACA,CAHA,uCAEA,CAJA,0CACA,CAIA,gBAJA,gBACA,oBADA,gBAIA,wBAEJ,gBAGE,6BACA,YAHA,iBAGA,gCACA,iEAEA,6CACA,sDACA,0BADA,wBACA,0BACA,oIAIA,mBAFA,YAEA,qBACA,0CAIE,uBAEF,CAHA,yBACE,CAEF,iDACE,mFAKJ,oCACE,CANE,aAKJ,CACE,qEAIA,YAFA,WAEA,CAHA,aACA,CAEA,gBACE,4BACA,sBADA,aACA,gCAMF,oCACA,yDACA,2CAEA,qBAGE,kBAEA,CACA,mCAIF,CARE,YACA,CAOF,iCAEE,CAPA,oBACA,CAQA,oBACE,uDAEJ,sDAGA,CAHA,cAGA,0BACE,oDAIA,oCACA,4BACA,sBAGA,cAEA,oFAGA,sBAEA,yDACE,CAIF,iBAJE,wBAIF,6CAHE,6CAKA,eACA,aACA,CADA,cACA,yCAGJ,kBACE,CAKA,iDAEA,CARF,aACE,4CAGA,kBAIA,wEAGA,wDAGA,kCAOA,iDAGA,CAPF,WAEE,sCAEA,CAJF,2CACE,CAMA,qCACA,+BARF,kBACE,qCAOA,iBAsBA,sBACE,CAvBF,WAKA,CACE,0DAIF,CALA,uDACE,CANF,sBAqBA,4CACA,CALA,gRAIA,YAEE,6CAEN,mCAEE,+CASA,6EAIA,4BChNA,SDmNA,qFCnNA,gDACA,sCAGA,qCACA,sDACA,CAKA,kDAGA,CARA,0CAQA,kBAGA,YACA,sBACA,iBAFA,gBADF,YACE,CAHA,SAKA,kBAEA,SAFA,iBAEA,uEAGA,CAEE,6CAFF,oCAgBI,CAdF,yBACE,qBACF,CAGF,oBACE,CAIF,WACE,CALA,2CAGA,uBACF,CACE,mFAGE,CALF,qBAEA,UAGE,gCAIF,sDAEA,CALE,oCAKF,yCC7CJ,oCACE,CD+CA,yXAQE,sCCrDJ,wCAGA,oCACE","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/variables/_layout.scss","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote, p\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto-light\n display: block\n\n @media (prefers-color-scheme: dark)\n .theme-toggle svg.theme-icon-when-auto-dark\n display: block\n .theme-toggle svg.theme-icon-when-auto-light\n display: none\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n --font-stack--headings: var(--font-stack);\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8,'),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"info\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"question\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8,')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #6b6f76; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #0a4bff;\n --color-brand-content: #2757dd;\n --color-brand-visited: #872ee0;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n\n --color-api-added: #21632c;\n --color-api-added-border: #38a84d;\n --color-api-changed: #046172;\n --color-api-changed-border: #06a1bc;\n --color-api-deprecated: #605706;\n --color-api-deprecated-border: #f0d90f;\n --color-api-removed: #b30000;\n --color-api-removed-border: #ff5c5c;\n\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline--hover: var(--color-foreground-border);\n\n --color-link--visited: var(--color-brand-visited);\n --color-link-underline--visited: var(--color-background-border);\n --color-link--visited--hover: var(--color-brand-visited);\n --color-link-underline--visited--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #cfd0d0; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #3d94ff;\n --color-brand-content: #5ca5ff;\n --color-brand-visited: #b27aeb;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n --color-api-added: #3db854;\n --color-api-added-border: #267334;\n --color-api-changed: #09b0ce;\n --color-api-changed-border: #056d80;\n --color-api-deprecated: #b1a10b;\n --color-api-deprecated-border: #6e6407;\n --color-api-removed: #ff7575;\n --color-api-removed-border: #b03b3b;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-family: var(--font-stack--headings)\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:visited\n color: var(--color-link--visited)\n text-decoration-color: var(--color-link-underline--visited)\n &:hover\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &:visited\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n.skip-to-content\n position: fixed\n padding: 1rem\n border-radius: 1rem\n left: 0.25rem\n top: 0.25rem\n z-index: 40\n background: var(--color-background-primary)\n color: var(--color-foreground-primary)\n\n transform: translateY(-200%)\n transition: transform 300ms ease-in-out\n\n &:focus-within\n transform: translateY(0%)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n overflow-wrap: break-word\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n display: flex\n\n.theme-toggle\n display: flex\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n height: 1.25rem\n width: 1.25rem\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n display: flex\n align-items: center\n justify-content: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: 1.5rem\n width: 1.5rem\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page, .view-this-page\n svg\n color: inherit\n height: 1.25rem\n width: 1.25rem\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $content-padded-width + $sidebar-width)\n // Center the page\n .content\n margin-left: auto\n margin-right: auto\n padding: 0 $content-padding--small\n\n@media (max-width: $content-padded-width--small + $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon, .theme-toggle-header\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: 1.5rem\n width: 1.5rem\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: calc(var(--header-height) + 2.5rem)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n\n@media (max-width: $content-width + 2* $content-padding--small)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n article[role=main] aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","// Overall Layout Variables\n//\n// Because CSS variables can't be used in media queries. The fact that this\n// makes the layout non-user-configurable is a good thing.\n$content-padding: 3em;\n$content-padding--small: 1em;\n$content-width: 46em;\n$sidebar-width: 15em;\n$content-padded-width: $content-width + 2 * $content-padding;\n$content-padded-width--small: $content-width + 2 * $content-padding--small;\n$full-width: $content-padded-width + 2 * $sidebar-width;\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\n.admonition p.admonition-title,\np.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 4.25rem\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\ndiv.versionadded,\ndiv.versionchanged,\ndiv.deprecated,\ndiv.versionremoved\n border-left: 0.1875rem solid\n border-radius: 0.125rem\n\n padding-left: 0.75rem\n\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\ndiv.versionadded\n border-color: var(--color-api-added-border)\n .versionmodified\n color: var(--color-api-added)\n\ndiv.versionchanged\n border-color: var(--color-api-changed-border)\n .versionmodified\n color: var(--color-api-changed)\n\ndiv.deprecated\n border-color: var(--color-api-deprecated-border)\n .versionmodified\n color: var(--color-api-deprecated)\n\ndiv.versionremoved\n border-color: var(--color-api-removed-border)\n .versionmodified\n color: var(--color-api-removed)\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n pre.literal-block &\n font-size: inherit\n padding: 0\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > *:not(span),\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n","[role=main] .table-wrapper.container\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 2.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(2.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(2.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n color: var(--color-sidebar-link-text)\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml,')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the