Codebase list python-geopandas / upstream/0.12.0
New upstream version 0.12.0 Bas Couwenberg 1 year, 6 months ago
72 changed file(s) with 1359 addition(s) and 428 deletion(s). Raw diff Collapse all Expand all
1111
1212 steps:
1313 - name: Checkout source
14 uses: actions/checkout@v2
14 uses: actions/checkout@v3
1515
1616 - name: Set up Python
17 uses: actions/setup-python@v2
17 uses: actions/setup-python@v4
1818 with:
1919 python-version: "3.x"
2020
2525 twine check --strict dist/*
2626
2727 - name: Publish distribution to PyPI
28 uses: pypa/gh-action-pypi-publish@master
28 uses: pypa/gh-action-pypi-publish@release/v1
2929 with:
3030 user: __token__
3131 password: ${{ secrets.PYPI_API_TOKEN }}
33 Development version
44 -------------------
55
6 Version 0.12 (October 24, 2022)
7 -------------------------------
8
9 The highlight of this release is the support for Shapely 2.0. This makes it possible to
10 test Shapely 2.0 (currently 2.0b1) alongside GeoPandas.
11
12 Note that if you also have PyGEOS installed, you need to set an environment variable
13 (`USE_PYGEOS=0`) before importing geopandas to actually test Shapely 2.0 features instead of PyGEOS. See
14 https://geopandas.org/en/latest/getting_started/install.html#using-the-optional-pygeos-dependency
15 for more details.
16
617 New features and improvements:
718
19 - Added ``normalize()`` method from shapely to GeoSeries/GeoDataframe (#2537).
20 - Added ``make_valid()`` method from shapely to GeoSeries/GeoDataframe (#2539).
21 - Added ``where`` filter to ``read_file`` (#2552).
22 - Updated the distributed natural earth datasets (*naturalearth_lowres* and
23 *naturalearth_cities*) to version 5.1 (#2555).
24
825 Deprecations and compatibility notes:
926
10 Bug fixes:
11
12 Notes on (optional) dependencies:
27 - Accessing the `crs` of a `GeoDataFrame` without active geometry column was deprecated
28 and this now raises an AttributeError (#2578).
29 - Resolved colormap-related warning in ``.explore()`` for recent Matplotlib versions
30 (#2596).
31
32 Bug fixes:
33
34 - Fix cryptic error message in ``geopandas.clip()`` when clipping with an empty geometry (#2589).
35 - Accessing `gdf.geometry` where the active geometry column is missing, and a column
36 named `"geometry"` is present will now raise an `AttributeError`, rather than
37 returning `gdf["geometry"]` (#2575).
38 - Combining GeoSeries/GeoDataFrames with ``pandas.concat`` will no longer silently
39 override CRS information if not all inputs have the same CRS (#2056).
1340
1441 Version 0.11.1 (July 24, 2022)
1542 ------------------------------
0 Copyright (c) 2013-2016, GeoPandas developers.
0 Copyright (c) 2013-2022, GeoPandas developers.
11 All rights reserved.
22
33 Redistribution and use in source and binary forms, with or without
88 * Redistributions in binary form must reproduce the above copyright notice,
99 this list of conditions and the following disclaimer in the documentation
1010 and/or other materials provided with the distribution.
11 * Neither the name of Enthought, Inc. nor the names of its contributors may
11 * Neither the name of GeoPandas nor the names of its contributors may
1212 be used to endorse or promote products derived from this software without
1313 specific prior written permission.
1414
44 - python=3.10
55 - cython
66 # required
7 - shapely
8 - fiona
97 - pyproj
108 - geos
119 - packaging
2725 # dev versions of packages
2826 - --pre --extra-index https://pypi.anaconda.org/scipy-wheels-nightly/simple
2927 - numpy
28 - fiona
3029 - git+https://github.com/pandas-dev/pandas.git@main
3130 - git+https://github.com/matplotlib/matplotlib.git@main
32 # - git+https://github.com/Toblerity/Shapely.git@main
31 - git+https://github.com/shapely/shapely.git@main
3332 - git+https://github.com/pygeos/pygeos.git@master
3433 - git+https://github.com/python-visualization/folium.git@main
3534 - git+https://github.com/geopandas/xyzservices.git@main
66 - pandas
77 - shapely
88 - fiona
9 - tiledb=2.11.3
910 - pyproj
1011 - pygeos
1112 - packaging
77 - shapely
88 # - fiona # build with only pyogrio
99 - libgdal
10 - tiledb=2.11.3
1011 - pyproj
1112 - pygeos
1213 - packaging
2627 - SQLalchemy
2728 - libspatialite
2829 - pyarrow
29 - pip
30 - pip:
31 - pyogrio
30 - pyogrio
33 dependencies:
44 - python=3.8
55 # required
6 - numpy=1.21 # pin to < 1.23 for compat with older shapely on defaults channel
67 - pandas
78 - shapely
89 - fiona
00 name: test
11 channels:
22 - conda-forge
3 # - conda-forge/label/shapely_dev
34 dependencies:
45 - python=3.9
56 # required
67 - pandas=1.3
7 - shapely
8 # - shapely=2
89 - fiona
10 - tiledb=2.11.3
911 - pyproj
10 - pygeos
12 # use this build to have one with only shapely 2.0 installed
13 # - pygeos
1114 - packaging
1215 # testing
1316 - pytest
3134 - pyarrow
3235 # doctest testing
3336 - pytest-doctestplus
34
37 - pip
38 - pip:
39 - --pre
40 - shapely==2.0b1
66 - pandas
77 - shapely
88 - fiona
9 - tiledb=2.11.3
910 - pyproj
1011 - packaging
1112 # testing
66 - pandas=1.2
77 - shapely
88 - fiona
9 - tiledb=2.11.3
910 - pyproj
1011 - pygeos
1112 - packaging
11 channels:
22 - conda-forge
33 dependencies:
4 - python=3.9.7
5 - pandas=1.3.2
6 - shapely=1.7.1
7 - fiona=1.8.20
8 - pyproj=3.2.1
9 - rtree=0.9.7
10 - geopy=2.2.0
11 - matplotlib=3.4.3
12 - mapclassify=2.4.3
13 - sphinx=4.2.0
14 - pydata-sphinx-theme=0.6.3
15 - numpydoc=1.1.0
16 - ipython=7.27.0
17 - pillow=8.3.2
18 - mock=4.0.3
19 - cartopy=0.20.0
20 - pyepsg=0.4.0
21 - contextily=1.1.0
22 - rasterio=1.2.8
23 - geoplot=0.4.4
24 - sphinx-gallery=0.9.0
25 - jinja2=3.0.1
26 - doc2dash=2.3.0
27 - matplotlib-scalebar=0.7.2
4 - python
5 - pandas
6 - shapely
7 - fiona
8 - pyproj
9 - rtree
10 - geopy
11 - matplotlib
12 - mapclassify
13 - sphinx
14 - pydata-sphinx-theme
15 - numpydoc
16 - ipython
17 - pillow
18 - mock
19 - cartopy
20 - pyepsg
21 - contextily
22 - rasterio
23 - geoplot
24 - sphinx-gallery
25 - jinja2
26 - doc2dash
27 - matplotlib-scalebar
2828 # specify additional dependencies to reduce solving for conda
29 - gdal=3.3.2
30 - libgdal=3.3.2
31 - proj=8.0.1
32 - geos=3.9.1
33 - nbsphinx=0.8.7
34 - jupyter_client=7.0.3
35 - ipykernel=6.4.1
36 - myst-parser=0.15.2
37 - folium=0.12.0
38 - libpysal=4.5.1
39 - pygeos=0.10.2
40 - xyzservices=2021.9.1
41 - packaging=21.0
29 - gdal
30 - libgdal
31 - proj
32 - geos
33 - nbsphinx
34 - jupyter_client
35 - ipykernel
36 - myst-parser
37 - folium
38 - libpysal
39 - pygeos
40 - xyzservices
41 - packaging
4242 - pip
4343 - pip:
4444 - sphinx-toggleprompt
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><line x1="120.15" y1="48.9" x2="162.49" y2="48.9" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="161.03 53.89 169.67 48.9 161.03 43.91 161.03 53.89" style="fill:#1d1d1b"/><circle cx="45.9" cy="48.9" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="48.9" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><g style="opacity:0.8"><circle cx="214.68" cy="48.9" r="34.98" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="48.9" r="34.98" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><path d="M214.68,48.9a35,35,0,0,1,17.48-30.29,35,35,0,1,0,0,60.57A34.93,34.93,0,0,1,214.68,48.9Z" style="fill:#fec905;opacity:0.8"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><line x1="120.15" y1="48.9" x2="162.49" y2="48.9" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="161.03 53.89 169.67 48.9 161.03 43.91 161.03 53.89" style="fill:#139c5a"/><circle cx="45.9" cy="48.9" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="48.9" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><g style="opacity:0.8"><circle cx="214.68" cy="48.9" r="34.98" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="48.9" r="34.98" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><path d="M214.68,48.9a35,35,0,0,1,17.48-30.29,35,35,0,1,0,0,60.57A34.93,34.93,0,0,1,214.68,48.9Z" style="fill:#fec905;opacity:0.8"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><g style="opacity:0.8"><circle cx="214.68" cy="51.28" r="34.98" transform="matrix(0.94, -0.33, 0.33, 0.94, -4.87, 73.95)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="51.28" r="34.98" transform="translate(74.78 236.69) rotate(-58.28)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><line x1="120.15" y1="51.28" x2="162.49" y2="51.28" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="161.03 56.27 169.67 51.28 161.03 46.3 161.03 56.27" style="fill:#1d1d1b"/><circle cx="45.9" cy="51.28" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="51.28" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><ellipse cx="232.16" cy="51.28" rx="17.49" ry="30.29" style="fill:#fec905;opacity:0.8"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><g style="opacity:0.8"><circle cx="214.68" cy="51.28" r="34.98" transform="matrix(0.94, -0.33, 0.33, 0.94, -4.87, 73.95)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="51.28" r="34.98" transform="translate(74.78 236.69) rotate(-58.28)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><line x1="120.15" y1="51.28" x2="162.49" y2="51.28" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="161.03 56.27 169.67 51.28 161.03 46.3 161.03 56.27" style="fill:#139c5a"/><circle cx="45.9" cy="51.28" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="51.28" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><ellipse cx="232.16" cy="51.28" rx="17.49" ry="30.29" style="fill:#fec905;opacity:0.8"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><g style="opacity:0.8"><circle cx="214.68" cy="51.28" r="34.98" transform="matrix(0.94, -0.33, 0.33, 0.94, -4.87, 73.95)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="51.28" r="34.98" transform="translate(74.78 236.69) rotate(-58.28)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><line x1="120.15" y1="51.28" x2="162.49" y2="51.28" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="161.03 56.27 169.67 51.28 161.03 46.3 161.03 56.27" style="fill:#1d1d1b"/><circle cx="45.9" cy="51.28" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="51.28" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><g style="opacity:0.8"><path d="M214.68,51.28A35,35,0,0,1,232.16,21a35,35,0,1,0,0,60.57A35,35,0,0,1,214.68,51.28Z" style="fill:#fec905"/><path d="M249.65,16.31A34.81,34.81,0,0,0,232.16,21a35,35,0,0,1,0,60.57,35,35,0,1,0,17.49-65.26Z" style="fill:#fec905"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><g style="opacity:0.8"><circle cx="214.68" cy="51.28" r="34.98" transform="matrix(0.94, -0.33, 0.33, 0.94, -4.87, 73.95)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="51.28" r="34.98" transform="translate(74.78 236.69) rotate(-58.28)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><line x1="120.15" y1="51.28" x2="162.49" y2="51.28" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="161.03 56.27 169.67 51.28 161.03 46.3 161.03 56.27" style="fill:#139c5a"/><circle cx="45.9" cy="51.28" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="51.28" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><g style="opacity:0.8"><path d="M214.68,51.28A35,35,0,0,1,232.16,21a35,35,0,1,0,0,60.57A35,35,0,0,1,214.68,51.28Z" style="fill:#fec905"/><path d="M249.65,16.31A34.81,34.81,0,0,0,232.16,21a35,35,0,0,1,0,60.57,35,35,0,1,0,17.49-65.26Z" style="fill:#fec905"/></g></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><g style="opacity:0.8"><circle cx="214.68" cy="50.49" r="34.98" transform="matrix(0.94, -0.33, 0.33, 0.94, -4.61, 73.91)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="50.49" r="34.98" transform="translate(75.45 236.31) rotate(-58.28)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><line x1="120.15" y1="50.49" x2="162.49" y2="50.49" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="161.03 55.48 169.67 50.49 161.03 45.5 161.03 55.48" style="fill:#1d1d1b"/><circle cx="45.9" cy="50.49" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="50.49" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><path d="M249.65,15.51a34.91,34.91,0,0,0-17.49,4.69,35,35,0,1,0,0,60.57,35,35,0,1,0,17.49-65.26Z" style="fill:#fec905;opacity:0.8"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="105.44mm" height="35.61mm" viewBox="0 0 298.88 100.95"><g style="opacity:0.8"><circle cx="214.68" cy="50.49" r="34.98" transform="matrix(0.94, -0.33, 0.33, 0.94, -4.61, 73.91)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><g style="opacity:0.8"><circle cx="249.65" cy="50.49" r="34.98" transform="translate(75.45 236.31) rotate(-58.28)" style="fill:none;stroke:#fec905;stroke-miterlimit:10;stroke-dasharray:1.9972946643829346,1.9972946643829346"/></g><line x1="120.15" y1="50.49" x2="162.49" y2="50.49" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="161.03 55.48 169.67 50.49 161.03 45.5 161.03 55.48" style="fill:#139c5a"/><circle cx="45.9" cy="50.49" r="34.98" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><circle cx="80.88" cy="50.49" r="34.98" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><path d="M249.65,15.51a34.91,34.91,0,0,0-17.49,4.69,35,35,0,1,0,0,60.57,35,35,0,1,0,17.49-65.26Z" style="fill:#fec905;opacity:0.8"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="115.16mm" height="58.15mm" viewBox="0 0 326.44 164.84"><rect x="5.24" y="27.78" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="5.24" y="46.88" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="5.24" y="65.98" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="5.24" y="85.08" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="5.24" y="104.19" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="48.04" y="27.78" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="8.68" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="48.04" y="46.88" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="65.98" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="85.08" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="104.19" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="194.49" y="27.78" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="194.49" y="46.88" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="194.49" y="65.98" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="194.49" y="85.08" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="194.49" y="104.19" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="237.29" y="27.78" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="8.68" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="237.29" y="46.88" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="65.98" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="85.08" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="104.19" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><line x1="138.48" y1="37.33" x2="180.83" y2="37.33" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="179.37 42.32 188 37.33 179.37 32.35 179.37 42.32" style="fill:#1d1d1b"/><line x1="138.48" y1="56.43" x2="180.83" y2="56.43" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="179.37 61.42 188 56.43 179.37 51.45 179.37 61.42" style="fill:#1d1d1b"/><line x1="138.48" y1="75.53" x2="180.83" y2="75.53" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="179.37 80.52 188 75.53 179.37 70.55 179.37 80.52" style="fill:#1d1d1b"/><line x1="138.48" y1="94.64" x2="180.83" y2="94.64" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="179.37 99.62 188 94.64 179.37 89.65 179.37 99.62" style="fill:#1d1d1b"/><line x1="138.48" y1="113.74" x2="180.83" y2="113.74" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="179.37 118.72 188 113.74 179.37 108.75 179.37 118.72" style="fill:#1d1d1b"/><rect x="3.19" y="25.4" width="42.25" height="99.95" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10;stroke-width:0.5px"/><path d="M7.38,143.15H9.76v-4.21H7.68v-1.19H11v5.4H13v1.2H7.38Zm1.9-7.21a.73.73,0,0,1,.22-.56.84.84,0,0,1,.59-.21h.29a.84.84,0,0,1,.6.21.77.77,0,0,1,.22.56.75.75,0,0,1-.22.55.85.85,0,0,1-.61.2h-.28a.83.83,0,0,1-.59-.2A.71.71,0,0,1,9.28,135.94Z" style="fill:#1d1d1b"/><path d="M14.46,137.75h1.25v1.14h.11a1.48,1.48,0,0,1,.59-.94,2,2,0,0,1,1.17-.32,2.4,2.4,0,0,1,.92.17,1.89,1.89,0,0,1,.68.49,2.13,2.13,0,0,1,.43.75,3,3,0,0,1,.14,1v4.34H18.43v-4.16a1.5,1.5,0,0,0-.34-1.06,1.27,1.27,0,0,0-1-.37,1.28,1.28,0,0,0-1,.39,1.57,1.57,0,0,0-.36,1.08v4.12H14.46Z" style="fill:#1d1d1b"/><path d="M21.54,140.21a3.49,3.49,0,0,1,.16-1.07,2.29,2.29,0,0,1,.46-.81,1.85,1.85,0,0,1,.71-.52,2.34,2.34,0,0,1,.93-.18A2,2,0,0,1,25,138a1.47,1.47,0,0,1,.61.93h.11l0-.41c0-.12,0-.24,0-.38s0-.25,0-.35v-2H27v8.64H25.71v-1.14H25.6a1.47,1.47,0,0,1-.61.93,2,2,0,0,1-1.19.33,2.34,2.34,0,0,1-.93-.18,1.85,1.85,0,0,1-.71-.52,2.25,2.25,0,0,1-.46-.82,3.6,3.6,0,0,1-.16-1.08Zm1.32,0v1.62a1.49,1.49,0,0,0,.38,1.07,1.35,1.35,0,0,0,1,.4,1.28,1.28,0,0,0,1-.4,1.45,1.45,0,0,0,.37-1v-1.64a1.47,1.47,0,0,0-.37-1.06,1.3,1.3,0,0,0-1-.4,1.38,1.38,0,0,0-1,.39A1.49,1.49,0,0,0,22.86,140.23Z" style="fill:#1d1d1b"/><path d="M28.74,140.19a3,3,0,0,1,.19-1.07,2.27,2.27,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.24,2.24,0,0,1,.55.8,2.8,2.8,0,0,1,.19,1.07v1.21H30.05v.47a1.49,1.49,0,0,0,.39,1.1,1.46,1.46,0,0,0,1.07.4,2.34,2.34,0,0,0,.88-.16,1,1,0,0,0,.54-.47h1.3a2.29,2.29,0,0,1-.35.72,2.23,2.23,0,0,1-.6.54,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.74,2.74,0,0,1-.2-1.06Zm1.31.25H33v-.25a1.35,1.35,0,0,0-1.47-1.46,1.34,1.34,0,0,0-1.46,1.46Z" style="fill:#1d1d1b"/><path d="M38,141l-2.23-3.2h1.53l1.23,1.86a1.05,1.05,0,0,1,.15.3.43.43,0,0,1,0,.13h.06a.43.43,0,0,1,0-.13,1,1,0,0,1,.15-.3l1.24-1.86H41.7l-2.22,3.19,2.37,3.41H40.31l-1.33-2a.59.59,0,0,1-.1-.17l-.07-.14-.06-.14h-.07s0,.1-.06.15l-.06.14a1.4,1.4,0,0,1-.1.16l-1.35,2H35.58Z" style="fill:#1d1d1b"/><rect x="46.28" y="6.23" width="86.81" height="119.12" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10;stroke-width:0.5px"/><path d="M135.05,144.47a3.23,3.23,0,0,1-1.15-.19,2.52,2.52,0,0,1-.87-.52,2.36,2.36,0,0,1-.55-.83,2.6,2.6,0,0,1-.2-1.06v-1.65a2.65,2.65,0,0,1,.2-1.07,2.32,2.32,0,0,1,.55-.82,2.54,2.54,0,0,1,.87-.53,3.76,3.76,0,0,1,2.3,0,2.38,2.38,0,0,1,.87.52,2.32,2.32,0,0,1,.55.82,2.59,2.59,0,0,1,.2,1.07v1.66a2.83,2.83,0,0,1-.19,1.07,2.24,2.24,0,0,1-.55.82,2.34,2.34,0,0,1-.88.52A3.23,3.23,0,0,1,135.05,144.47Zm-1.45-2.6a1.5,1.5,0,0,0,2.51,1,1.4,1.4,0,0,0,.39-1v-1.65a1.39,1.39,0,0,0-.39-1.05,1.64,1.64,0,0,0-2.12,0,1.39,1.39,0,0,0-.39,1.05Z" style="fill:#1d1d1b"/><path d="M139.61,137.75h1.26v1.14h.1a1.46,1.46,0,0,1,.6-.93,2.07,2.07,0,0,1,1.2-.33,2.32,2.32,0,0,1,.92.18,1.85,1.85,0,0,1,.71.52,2.29,2.29,0,0,1,.46.81,3.21,3.21,0,0,1,.16,1.07v1.66a3.31,3.31,0,0,1-.16,1.08,2.25,2.25,0,0,1-.46.82,1.85,1.85,0,0,1-.71.52,2.32,2.32,0,0,1-.92.18,2.07,2.07,0,0,1-1.2-.33,1.46,1.46,0,0,1-.6-.93h-.1a1,1,0,0,0,0,.13,2.33,2.33,0,0,1,0,.29c0,.11,0,.23,0,.36s0,.25,0,.36v2h-1.32Zm1.32,2.48v1.64a1.45,1.45,0,0,0,.37,1,1.25,1.25,0,0,0,1,.4,1.33,1.33,0,0,0,1-.4,1.45,1.45,0,0,0,.38-1.07v-1.62a1.45,1.45,0,0,0-.38-1.07,1.36,1.36,0,0,0-1-.39,1.28,1.28,0,0,0-1,.4A1.47,1.47,0,0,0,140.93,140.23Z" style="fill:#1d1d1b"/><path d="M146.68,140.19a2.8,2.8,0,0,1,.19-1.07,2.24,2.24,0,0,1,.55-.8,2.46,2.46,0,0,1,.88-.51,3.43,3.43,0,0,1,1.15-.18,3.47,3.47,0,0,1,1.15.18,2.6,2.6,0,0,1,.87.51,2.24,2.24,0,0,1,.55.8,3,3,0,0,1,.19,1.07v1.21H148v.47a1.46,1.46,0,0,0,.4,1.1,1.44,1.44,0,0,0,1.07.4,2.29,2.29,0,0,0,.87-.16,1,1,0,0,0,.54-.47h1.3a2.1,2.1,0,0,1-.35.72,2.35,2.35,0,0,1-.59.54,2.9,2.9,0,0,1-.8.35,3.85,3.85,0,0,1-1,.12,3.43,3.43,0,0,1-1.15-.18,2.38,2.38,0,0,1-.87-.52,2.2,2.2,0,0,1-.55-.81,2.57,2.57,0,0,1-.2-1.06Zm1.3.25h2.93v-.25a1.52,1.52,0,0,0-2.54-1.07,1.42,1.42,0,0,0-.39,1.07Z" style="fill:#1d1d1b"/><path d="M155.52,137.75v1.14h.11a1.45,1.45,0,0,1,.62-.93,2.11,2.11,0,0,1,1.22-.33,2.15,2.15,0,0,1,1.65.65,2.61,2.61,0,0,1,.6,1.82v.43h-1.35v-.3a1.5,1.5,0,0,0-.38-1.08,1.32,1.32,0,0,0-1-.39,1.3,1.3,0,0,0-1,.39,1.53,1.53,0,0,0-.38,1.08v4.12h-1.32v-6.6Z" style="fill:#1d1d1b"/><path d="M160.92,142.47a1.9,1.9,0,0,1,.67-1.53,2.71,2.71,0,0,1,1.8-.56h1.79v-.55a1,1,0,0,0-.36-.83,1.67,1.67,0,0,0-1-.29,1.82,1.82,0,0,0-.88.19.9.9,0,0,0-.48.52h-1.29a1.94,1.94,0,0,1,.87-1.31,3.17,3.17,0,0,1,1.79-.48,3.1,3.1,0,0,1,2,.58,1.91,1.91,0,0,1,.72,1.58v4.56h-1.22v-1.28h-.1a1.56,1.56,0,0,1-.7,1,2.51,2.51,0,0,1-1.41.38,2.18,2.18,0,0,1-1.57-.55A1.92,1.92,0,0,1,160.92,142.47Zm1.32-.11a1,1,0,0,0,.33.78,1.37,1.37,0,0,0,.91.27,2.43,2.43,0,0,0,.68-.09,2,2,0,0,0,.54-.27,1.4,1.4,0,0,0,.36-.41,1.13,1.13,0,0,0,.12-.51v-.83h-1.77a1.24,1.24,0,0,0-.86.28A1,1,0,0,0,162.24,142.36Z" style="fill:#1d1d1b"/><path d="M168.07,137.75h1.86v-2h1.32v2h2.53v1.19h-2.53v3.51a.69.69,0,0,0,.19.51.73.73,0,0,0,.54.19h1.68v1.2h-1.74a2,2,0,0,1-1.45-.52,1.81,1.81,0,0,1-.54-1.38v-3.51h-1.86Z" style="fill:#1d1d1b"/><path d="M175.72,143.15h2.37v-4.21H176v-1.19h3.36v5.4h1.93v1.2h-5.59Zm1.89-7.21a.77.77,0,0,1,.22-.56.84.84,0,0,1,.6-.21h.29a.84.84,0,0,1,.59.21.73.73,0,0,1,.22.56.71.71,0,0,1-.22.55.85.85,0,0,1-.61.2h-.27a.84.84,0,0,1-.6-.2A.75.75,0,0,1,177.61,135.94Z" style="fill:#1d1d1b"/><path d="M185.45,144.47a3.19,3.19,0,0,1-1.15-.19,2.52,2.52,0,0,1-.87-.52,2.36,2.36,0,0,1-.55-.83,2.6,2.6,0,0,1-.2-1.06v-1.65a2.65,2.65,0,0,1,.2-1.07,2.32,2.32,0,0,1,.55-.82,2.54,2.54,0,0,1,.87-.53,3.43,3.43,0,0,1,1.15-.18,3.47,3.47,0,0,1,1.15.18,2.46,2.46,0,0,1,.87.52,2.32,2.32,0,0,1,.55.82,2.76,2.76,0,0,1,.2,1.07v1.66a2.83,2.83,0,0,1-.19,1.07,2.24,2.24,0,0,1-.55.82,2.42,2.42,0,0,1-.88.52A3.23,3.23,0,0,1,185.45,144.47Zm-1.45-2.6a1.4,1.4,0,0,0,.38,1,1.65,1.65,0,0,0,2.13,0,1.4,1.4,0,0,0,.39-1v-1.65a1.39,1.39,0,0,0-.39-1.05,1.64,1.64,0,0,0-2.12,0,1.39,1.39,0,0,0-.39,1.05Z" style="fill:#1d1d1b"/><path d="M190,137.75h1.24v1.14h.11a1.52,1.52,0,0,1,.59-.94,2,2,0,0,1,1.18-.32,2.34,2.34,0,0,1,.91.17,2,2,0,0,1,.69.49,2,2,0,0,1,.42.75,3,3,0,0,1,.15,1v4.34H194v-4.16a1.5,1.5,0,0,0-.35-1.06,1.24,1.24,0,0,0-1-.37,1.26,1.26,0,0,0-1,.39,1.57,1.57,0,0,0-.36,1.08v4.12H190Z" style="fill:#1d1d1b"/><path d="M61.67,140.17a3.51,3.51,0,0,1,.15-1,2.33,2.33,0,0,1,.46-.8,2.05,2.05,0,0,1,.72-.51,2.34,2.34,0,0,1,.93-.18,2.1,2.1,0,0,1,1.23.35,1.56,1.56,0,0,1,.63,1h.09v-1.2h1.25V144a2.3,2.3,0,0,1-.72,1.79,2.83,2.83,0,0,1-2,.65h-1.7v-1.13h1.7a1.36,1.36,0,0,0,1-.35,1.27,1.27,0,0,0,.37-1v-.22l.05-1.2h-.08a1.61,1.61,0,0,1-.65,1,2,2,0,0,1-1.22.35,2.34,2.34,0,0,1-.93-.18,2.11,2.11,0,0,1-.71-.51,2.31,2.31,0,0,1-.45-.8,3.13,3.13,0,0,1-.16-1.05ZM63,141.29a1.31,1.31,0,0,0,1.4,1.42,1.31,1.31,0,0,0,1.42-1.42v-1.1a1.31,1.31,0,0,0-1.42-1.42,1.31,1.31,0,0,0-1.4,1.42Z" style="fill:#1d1d1b"/><path d="M68.91,140.19a3,3,0,0,1,.19-1.07,2.27,2.27,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.12,2.12,0,0,1,.55.8,2.79,2.79,0,0,1,.2,1.07v1.21H70.22v.47a1.49,1.49,0,0,0,.39,1.1,1.46,1.46,0,0,0,1.07.4,2.34,2.34,0,0,0,.88-.16,1,1,0,0,0,.54-.47h1.3a2.1,2.1,0,0,1-.35.72,2.35,2.35,0,0,1-.59.54,3,3,0,0,1-.81.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.74,2.74,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.47,1.47,0,1,0-2.93,0Z" style="fill:#1d1d1b"/><path d="M78.88,144.47a3.17,3.17,0,0,1-1.14-.19,2.52,2.52,0,0,1-.87-.52,2.39,2.39,0,0,1-.56-.83,2.78,2.78,0,0,1-.2-1.06v-1.65a2.83,2.83,0,0,1,.2-1.07,2.35,2.35,0,0,1,.56-.82,2.54,2.54,0,0,1,.87-.53,3.73,3.73,0,0,1,2.29,0,2.38,2.38,0,0,1,.87.52,2.35,2.35,0,0,1,.56.82,2.76,2.76,0,0,1,.2,1.07v1.66a2.83,2.83,0,0,1-.2,1.07,2.12,2.12,0,0,1-.55.82,2.38,2.38,0,0,1-.87.52A3.28,3.28,0,0,1,78.88,144.47Zm-1.45-2.6a1.35,1.35,0,0,0,1.45,1.44,1.45,1.45,0,0,0,1.07-.39,1.4,1.4,0,0,0,.39-1v-1.65a1.39,1.39,0,0,0-.39-1.05,1.65,1.65,0,0,0-2.13,0,1.39,1.39,0,0,0-.39,1.05Z" style="fill:#1d1d1b"/><path d="M83.14,144.35v-6.6h1.1v1h.09a1.24,1.24,0,0,1,.32-.8,1,1,0,0,1,.76-.29.91.91,0,0,1,.72.28,1.62,1.62,0,0,1,.39.81h.08a1.15,1.15,0,0,1,.33-.8,1,1,0,0,1,.77-.29,1.19,1.19,0,0,1,1,.45,1.93,1.93,0,0,1,.37,1.24v5H87.82v-5a1,1,0,0,0-.15-.59.57.57,0,0,0-.46-.2q-.63,0-.63.84v4.92h-1v-5a.94.94,0,0,0-.16-.59.63.63,0,0,0-.48-.2q-.63,0-.63.84v4.92Z" style="fill:#1d1d1b"/><path d="M90.51,140.19a3,3,0,0,1,.19-1.07,2.27,2.27,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.12,2.12,0,0,1,.55.8,2.79,2.79,0,0,1,.2,1.07v1.21H91.82v.47a1.49,1.49,0,0,0,.39,1.1,1.46,1.46,0,0,0,1.07.4,2.34,2.34,0,0,0,.88-.16,1,1,0,0,0,.54-.47H96a2.1,2.1,0,0,1-.35.72,2.35,2.35,0,0,1-.59.54,3,3,0,0,1-.81.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.74,2.74,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.35,1.35,0,0,0-1.47-1.46,1.34,1.34,0,0,0-1.46,1.46Z" style="fill:#1d1d1b"/><path d="M97.51,137.75h1.86v-2h1.32v2h2.53v1.19h-2.53v3.51a.66.66,0,0,0,.19.51.73.73,0,0,0,.54.19h1.68v1.2h-1.74a2,2,0,0,1-1.46-.52,1.84,1.84,0,0,1-.53-1.38v-3.51H97.51Z" style="fill:#1d1d1b"/><path d="M106.56,137.75v1.14h.1a1.48,1.48,0,0,1,.62-.93,2.14,2.14,0,0,1,1.22-.33,2.17,2.17,0,0,1,1.66.65,2.61,2.61,0,0,1,.6,1.82v.43H109.4v-.3a1.49,1.49,0,0,0-.37-1.08,1.35,1.35,0,0,0-1-.39,1.33,1.33,0,0,0-1,.39,1.52,1.52,0,0,0-.37,1.08v4.12h-1.32v-6.6Z" style="fill:#1d1d1b"/><path d="M111.79,137.75h1.44l1.39,3.64a4.26,4.26,0,0,1,.15.47,4.31,4.31,0,0,1,.09.44l.06.43h.1a3.28,3.28,0,0,1,0-.43c0-.13.06-.27.09-.43s.09-.32.14-.48l1.3-3.64H118l-3.17,8.64h-1.39l.91-2.46Z" style="fill:#1d1d1b"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="115.16mm" height="58.15mm" viewBox="0 0 326.44 164.84"><rect x="5.24" y="27.78" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="5.24" y="46.88" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="5.24" y="65.98" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="5.24" y="85.08" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="5.24" y="104.19" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="48.04" y="27.78" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="8.68" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="48.04" y="46.88" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="65.98" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="85.08" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="48.04" y="104.19" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="194.49" y="27.78" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="194.49" y="46.88" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="194.49" y="65.98" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="194.49" y="85.08" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="194.49" y="104.19" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="237.29" y="27.78" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="8.68" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="237.29" y="46.88" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="65.98" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="85.08" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="237.29" y="104.19" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><line x1="138.48" y1="37.33" x2="180.83" y2="37.33" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="179.37 42.32 188 37.33 179.37 32.35 179.37 42.32" style="fill:#139c5a"/><line x1="138.48" y1="56.43" x2="180.83" y2="56.43" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="179.37 61.42 188 56.43 179.37 51.45 179.37 61.42" style="fill:#139c5a"/><line x1="138.48" y1="75.53" x2="180.83" y2="75.53" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="179.37 80.52 188 75.53 179.37 70.55 179.37 80.52" style="fill:#139c5a"/><line x1="138.48" y1="94.64" x2="180.83" y2="94.64" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="179.37 99.62 188 94.64 179.37 89.65 179.37 99.62" style="fill:#139c5a"/><line x1="138.48" y1="113.74" x2="180.83" y2="113.74" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="179.37 118.72 188 113.74 179.37 108.75 179.37 118.72" style="fill:#139c5a"/><rect x="3.19" y="25.4" width="42.25" height="99.95" style="fill:none;stroke:#139c5a;stroke-miterlimit:10;stroke-width:0.5px"/><path d="M7.38,143.15H9.76v-4.21H7.68v-1.19H11v5.4H13v1.2H7.38Zm1.9-7.21a.73.73,0,0,1,.22-.56.84.84,0,0,1,.59-.21h.29a.84.84,0,0,1,.6.21.77.77,0,0,1,.22.56.75.75,0,0,1-.22.55.85.85,0,0,1-.61.2h-.28a.83.83,0,0,1-.59-.2A.71.71,0,0,1,9.28,135.94Z" style="fill:#139c5a"/><path d="M14.46,137.75h1.25v1.14h.11a1.48,1.48,0,0,1,.59-.94,2,2,0,0,1,1.17-.32,2.4,2.4,0,0,1,.92.17,1.89,1.89,0,0,1,.68.49,2.13,2.13,0,0,1,.43.75,3,3,0,0,1,.14,1v4.34H18.43v-4.16a1.5,1.5,0,0,0-.34-1.06,1.27,1.27,0,0,0-1-.37,1.28,1.28,0,0,0-1,.39,1.57,1.57,0,0,0-.36,1.08v4.12H14.46Z" style="fill:#139c5a"/><path d="M21.54,140.21a3.49,3.49,0,0,1,.16-1.07,2.29,2.29,0,0,1,.46-.81,1.85,1.85,0,0,1,.71-.52,2.34,2.34,0,0,1,.93-.18A2,2,0,0,1,25,138a1.47,1.47,0,0,1,.61.93h.11l0-.41c0-.12,0-.24,0-.38s0-.25,0-.35v-2H27v8.64H25.71v-1.14H25.6a1.47,1.47,0,0,1-.61.93,2,2,0,0,1-1.19.33,2.34,2.34,0,0,1-.93-.18,1.85,1.85,0,0,1-.71-.52,2.25,2.25,0,0,1-.46-.82,3.6,3.6,0,0,1-.16-1.08Zm1.32,0v1.62a1.49,1.49,0,0,0,.38,1.07,1.35,1.35,0,0,0,1,.4,1.28,1.28,0,0,0,1-.4,1.45,1.45,0,0,0,.37-1v-1.64a1.47,1.47,0,0,0-.37-1.06,1.3,1.3,0,0,0-1-.4,1.38,1.38,0,0,0-1,.39A1.49,1.49,0,0,0,22.86,140.23Z" style="fill:#139c5a"/><path d="M28.74,140.19a3,3,0,0,1,.19-1.07,2.27,2.27,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.24,2.24,0,0,1,.55.8,2.8,2.8,0,0,1,.19,1.07v1.21H30.05v.47a1.49,1.49,0,0,0,.39,1.1,1.46,1.46,0,0,0,1.07.4,2.34,2.34,0,0,0,.88-.16,1,1,0,0,0,.54-.47h1.3a2.29,2.29,0,0,1-.35.72,2.23,2.23,0,0,1-.6.54,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.74,2.74,0,0,1-.2-1.06Zm1.31.25H33v-.25a1.35,1.35,0,0,0-1.47-1.46,1.34,1.34,0,0,0-1.46,1.46Z" style="fill:#139c5a"/><path d="M38,141l-2.23-3.2h1.53l1.23,1.86a1.05,1.05,0,0,1,.15.3.43.43,0,0,1,0,.13h.06a.43.43,0,0,1,0-.13,1,1,0,0,1,.15-.3l1.24-1.86H41.7l-2.22,3.19,2.37,3.41H40.31l-1.33-2a.59.59,0,0,1-.1-.17l-.07-.14-.06-.14h-.07s0,.1-.06.15l-.06.14a1.4,1.4,0,0,1-.1.16l-1.35,2H35.58Z" style="fill:#139c5a"/><rect x="46.28" y="6.23" width="86.81" height="119.12" style="fill:none;stroke:#139c5a;stroke-miterlimit:10;stroke-width:0.5px"/><path d="M135.05,144.47a3.23,3.23,0,0,1-1.15-.19,2.52,2.52,0,0,1-.87-.52,2.36,2.36,0,0,1-.55-.83,2.6,2.6,0,0,1-.2-1.06v-1.65a2.65,2.65,0,0,1,.2-1.07,2.32,2.32,0,0,1,.55-.82,2.54,2.54,0,0,1,.87-.53,3.76,3.76,0,0,1,2.3,0,2.38,2.38,0,0,1,.87.52,2.32,2.32,0,0,1,.55.82,2.59,2.59,0,0,1,.2,1.07v1.66a2.83,2.83,0,0,1-.19,1.07,2.24,2.24,0,0,1-.55.82,2.34,2.34,0,0,1-.88.52A3.23,3.23,0,0,1,135.05,144.47Zm-1.45-2.6a1.5,1.5,0,0,0,2.51,1,1.4,1.4,0,0,0,.39-1v-1.65a1.39,1.39,0,0,0-.39-1.05,1.64,1.64,0,0,0-2.12,0,1.39,1.39,0,0,0-.39,1.05Z" style="fill:#139c5a"/><path d="M139.61,137.75h1.26v1.14h.1a1.46,1.46,0,0,1,.6-.93,2.07,2.07,0,0,1,1.2-.33,2.32,2.32,0,0,1,.92.18,1.85,1.85,0,0,1,.71.52,2.29,2.29,0,0,1,.46.81,3.21,3.21,0,0,1,.16,1.07v1.66a3.31,3.31,0,0,1-.16,1.08,2.25,2.25,0,0,1-.46.82,1.85,1.85,0,0,1-.71.52,2.32,2.32,0,0,1-.92.18,2.07,2.07,0,0,1-1.2-.33,1.46,1.46,0,0,1-.6-.93h-.1a1,1,0,0,0,0,.13,2.33,2.33,0,0,1,0,.29c0,.11,0,.23,0,.36s0,.25,0,.36v2h-1.32Zm1.32,2.48v1.64a1.45,1.45,0,0,0,.37,1,1.25,1.25,0,0,0,1,.4,1.33,1.33,0,0,0,1-.4,1.45,1.45,0,0,0,.38-1.07v-1.62a1.45,1.45,0,0,0-.38-1.07,1.36,1.36,0,0,0-1-.39,1.28,1.28,0,0,0-1,.4A1.47,1.47,0,0,0,140.93,140.23Z" style="fill:#139c5a"/><path d="M146.68,140.19a2.8,2.8,0,0,1,.19-1.07,2.24,2.24,0,0,1,.55-.8,2.46,2.46,0,0,1,.88-.51,3.43,3.43,0,0,1,1.15-.18,3.47,3.47,0,0,1,1.15.18,2.6,2.6,0,0,1,.87.51,2.24,2.24,0,0,1,.55.8,3,3,0,0,1,.19,1.07v1.21H148v.47a1.46,1.46,0,0,0,.4,1.1,1.44,1.44,0,0,0,1.07.4,2.29,2.29,0,0,0,.87-.16,1,1,0,0,0,.54-.47h1.3a2.1,2.1,0,0,1-.35.72,2.35,2.35,0,0,1-.59.54,2.9,2.9,0,0,1-.8.35,3.85,3.85,0,0,1-1,.12,3.43,3.43,0,0,1-1.15-.18,2.38,2.38,0,0,1-.87-.52,2.2,2.2,0,0,1-.55-.81,2.57,2.57,0,0,1-.2-1.06Zm1.3.25h2.93v-.25a1.52,1.52,0,0,0-2.54-1.07,1.42,1.42,0,0,0-.39,1.07Z" style="fill:#139c5a"/><path d="M155.52,137.75v1.14h.11a1.45,1.45,0,0,1,.62-.93,2.11,2.11,0,0,1,1.22-.33,2.15,2.15,0,0,1,1.65.65,2.61,2.61,0,0,1,.6,1.82v.43h-1.35v-.3a1.5,1.5,0,0,0-.38-1.08,1.32,1.32,0,0,0-1-.39,1.3,1.3,0,0,0-1,.39,1.53,1.53,0,0,0-.38,1.08v4.12h-1.32v-6.6Z" style="fill:#139c5a"/><path d="M160.92,142.47a1.9,1.9,0,0,1,.67-1.53,2.71,2.71,0,0,1,1.8-.56h1.79v-.55a1,1,0,0,0-.36-.83,1.67,1.67,0,0,0-1-.29,1.82,1.82,0,0,0-.88.19.9.9,0,0,0-.48.52h-1.29a1.94,1.94,0,0,1,.87-1.31,3.17,3.17,0,0,1,1.79-.48,3.1,3.1,0,0,1,2,.58,1.91,1.91,0,0,1,.72,1.58v4.56h-1.22v-1.28h-.1a1.56,1.56,0,0,1-.7,1,2.51,2.51,0,0,1-1.41.38,2.18,2.18,0,0,1-1.57-.55A1.92,1.92,0,0,1,160.92,142.47Zm1.32-.11a1,1,0,0,0,.33.78,1.37,1.37,0,0,0,.91.27,2.43,2.43,0,0,0,.68-.09,2,2,0,0,0,.54-.27,1.4,1.4,0,0,0,.36-.41,1.13,1.13,0,0,0,.12-.51v-.83h-1.77a1.24,1.24,0,0,0-.86.28A1,1,0,0,0,162.24,142.36Z" style="fill:#139c5a"/><path d="M168.07,137.75h1.86v-2h1.32v2h2.53v1.19h-2.53v3.51a.69.69,0,0,0,.19.51.73.73,0,0,0,.54.19h1.68v1.2h-1.74a2,2,0,0,1-1.45-.52,1.81,1.81,0,0,1-.54-1.38v-3.51h-1.86Z" style="fill:#139c5a"/><path d="M175.72,143.15h2.37v-4.21H176v-1.19h3.36v5.4h1.93v1.2h-5.59Zm1.89-7.21a.77.77,0,0,1,.22-.56.84.84,0,0,1,.6-.21h.29a.84.84,0,0,1,.59.21.73.73,0,0,1,.22.56.71.71,0,0,1-.22.55.85.85,0,0,1-.61.2h-.27a.84.84,0,0,1-.6-.2A.75.75,0,0,1,177.61,135.94Z" style="fill:#139c5a"/><path d="M185.45,144.47a3.19,3.19,0,0,1-1.15-.19,2.52,2.52,0,0,1-.87-.52,2.36,2.36,0,0,1-.55-.83,2.6,2.6,0,0,1-.2-1.06v-1.65a2.65,2.65,0,0,1,.2-1.07,2.32,2.32,0,0,1,.55-.82,2.54,2.54,0,0,1,.87-.53,3.43,3.43,0,0,1,1.15-.18,3.47,3.47,0,0,1,1.15.18,2.46,2.46,0,0,1,.87.52,2.32,2.32,0,0,1,.55.82,2.76,2.76,0,0,1,.2,1.07v1.66a2.83,2.83,0,0,1-.19,1.07,2.24,2.24,0,0,1-.55.82,2.42,2.42,0,0,1-.88.52A3.23,3.23,0,0,1,185.45,144.47Zm-1.45-2.6a1.4,1.4,0,0,0,.38,1,1.65,1.65,0,0,0,2.13,0,1.4,1.4,0,0,0,.39-1v-1.65a1.39,1.39,0,0,0-.39-1.05,1.64,1.64,0,0,0-2.12,0,1.39,1.39,0,0,0-.39,1.05Z" style="fill:#139c5a"/><path d="M190,137.75h1.24v1.14h.11a1.52,1.52,0,0,1,.59-.94,2,2,0,0,1,1.18-.32,2.34,2.34,0,0,1,.91.17,2,2,0,0,1,.69.49,2,2,0,0,1,.42.75,3,3,0,0,1,.15,1v4.34H194v-4.16a1.5,1.5,0,0,0-.35-1.06,1.24,1.24,0,0,0-1-.37,1.26,1.26,0,0,0-1,.39,1.57,1.57,0,0,0-.36,1.08v4.12H190Z" style="fill:#139c5a"/><path d="M61.67,140.17a3.51,3.51,0,0,1,.15-1,2.33,2.33,0,0,1,.46-.8,2.05,2.05,0,0,1,.72-.51,2.34,2.34,0,0,1,.93-.18,2.1,2.1,0,0,1,1.23.35,1.56,1.56,0,0,1,.63,1h.09v-1.2h1.25V144a2.3,2.3,0,0,1-.72,1.79,2.83,2.83,0,0,1-2,.65h-1.7v-1.13h1.7a1.36,1.36,0,0,0,1-.35,1.27,1.27,0,0,0,.37-1v-.22l.05-1.2h-.08a1.61,1.61,0,0,1-.65,1,2,2,0,0,1-1.22.35,2.34,2.34,0,0,1-.93-.18,2.11,2.11,0,0,1-.71-.51,2.31,2.31,0,0,1-.45-.8,3.13,3.13,0,0,1-.16-1.05ZM63,141.29a1.31,1.31,0,0,0,1.4,1.42,1.31,1.31,0,0,0,1.42-1.42v-1.1a1.31,1.31,0,0,0-1.42-1.42,1.31,1.31,0,0,0-1.4,1.42Z" style="fill:#139c5a"/><path d="M68.91,140.19a3,3,0,0,1,.19-1.07,2.27,2.27,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.12,2.12,0,0,1,.55.8,2.79,2.79,0,0,1,.2,1.07v1.21H70.22v.47a1.49,1.49,0,0,0,.39,1.1,1.46,1.46,0,0,0,1.07.4,2.34,2.34,0,0,0,.88-.16,1,1,0,0,0,.54-.47h1.3a2.1,2.1,0,0,1-.35.72,2.35,2.35,0,0,1-.59.54,3,3,0,0,1-.81.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.74,2.74,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.47,1.47,0,1,0-2.93,0Z" style="fill:#139c5a"/><path d="M78.88,144.47a3.17,3.17,0,0,1-1.14-.19,2.52,2.52,0,0,1-.87-.52,2.39,2.39,0,0,1-.56-.83,2.78,2.78,0,0,1-.2-1.06v-1.65a2.83,2.83,0,0,1,.2-1.07,2.35,2.35,0,0,1,.56-.82,2.54,2.54,0,0,1,.87-.53,3.73,3.73,0,0,1,2.29,0,2.38,2.38,0,0,1,.87.52,2.35,2.35,0,0,1,.56.82,2.76,2.76,0,0,1,.2,1.07v1.66a2.83,2.83,0,0,1-.2,1.07,2.12,2.12,0,0,1-.55.82,2.38,2.38,0,0,1-.87.52A3.28,3.28,0,0,1,78.88,144.47Zm-1.45-2.6a1.35,1.35,0,0,0,1.45,1.44,1.45,1.45,0,0,0,1.07-.39,1.4,1.4,0,0,0,.39-1v-1.65a1.39,1.39,0,0,0-.39-1.05,1.65,1.65,0,0,0-2.13,0,1.39,1.39,0,0,0-.39,1.05Z" style="fill:#139c5a"/><path d="M83.14,144.35v-6.6h1.1v1h.09a1.24,1.24,0,0,1,.32-.8,1,1,0,0,1,.76-.29.91.91,0,0,1,.72.28,1.62,1.62,0,0,1,.39.81h.08a1.15,1.15,0,0,1,.33-.8,1,1,0,0,1,.77-.29,1.19,1.19,0,0,1,1,.45,1.93,1.93,0,0,1,.37,1.24v5H87.82v-5a1,1,0,0,0-.15-.59.57.57,0,0,0-.46-.2q-.63,0-.63.84v4.92h-1v-5a.94.94,0,0,0-.16-.59.63.63,0,0,0-.48-.2q-.63,0-.63.84v4.92Z" style="fill:#139c5a"/><path d="M90.51,140.19a3,3,0,0,1,.19-1.07,2.27,2.27,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.12,2.12,0,0,1,.55.8,2.79,2.79,0,0,1,.2,1.07v1.21H91.82v.47a1.49,1.49,0,0,0,.39,1.1,1.46,1.46,0,0,0,1.07.4,2.34,2.34,0,0,0,.88-.16,1,1,0,0,0,.54-.47H96a2.1,2.1,0,0,1-.35.72,2.35,2.35,0,0,1-.59.54,3,3,0,0,1-.81.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.74,2.74,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.35,1.35,0,0,0-1.47-1.46,1.34,1.34,0,0,0-1.46,1.46Z" style="fill:#139c5a"/><path d="M97.51,137.75h1.86v-2h1.32v2h2.53v1.19h-2.53v3.51a.66.66,0,0,0,.19.51.73.73,0,0,0,.54.19h1.68v1.2h-1.74a2,2,0,0,1-1.46-.52,1.84,1.84,0,0,1-.53-1.38v-3.51H97.51Z" style="fill:#139c5a"/><path d="M106.56,137.75v1.14h.1a1.48,1.48,0,0,1,.62-.93,2.14,2.14,0,0,1,1.22-.33,2.17,2.17,0,0,1,1.66.65,2.61,2.61,0,0,1,.6,1.82v.43H109.4v-.3a1.49,1.49,0,0,0-.37-1.08,1.35,1.35,0,0,0-1-.39,1.33,1.33,0,0,0-1,.39,1.52,1.52,0,0,0-.37,1.08v4.12h-1.32v-6.6Z" style="fill:#139c5a"/><path d="M111.79,137.75h1.44l1.39,3.64a4.26,4.26,0,0,1,.15.47,4.31,4.31,0,0,1,.09.44l.06.43h.1a3.28,3.28,0,0,1,0-.43c0-.13.06-.27.09-.43s.09-.32.14-.48l1.3-3.64H118l-3.17,8.64h-1.39l.91-2.46Z" style="fill:#139c5a"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="255.6mm" height="57.81mm" viewBox="0 0 724.53 163.88"><rect x="11" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="11" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="11" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="11" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="11" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="53.8" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="53.8" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="200.25" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="200.25" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="200.25" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="200.25" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="200.25" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="243.05" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="243.05" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><line x1="144.24" y1="38.14" x2="187.07" y2="54.66" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="183.91 58.79 193.76 57.25 187.5 49.49 183.91 58.79" style="fill:#1d1d1b"/><line x1="144.24" y1="57.25" x2="188.08" y2="91.07" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="183.88 94.12 193.76 95.45 189.97 86.23 183.88 94.12" style="fill:#1d1d1b"/><line x1="144.24" y1="76.35" x2="188.08" y2="110.17" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="183.88 113.22 193.76 114.55 189.97 105.33 183.88 113.22" style="fill:#1d1d1b"/><line x1="144.24" y1="95.45" x2="189.07" y2="43.57" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="191.89 47.94 193.76 38.15 184.34 41.42 191.89 47.94" style="fill:#1d1d1b"/><line x1="144.24" y1="114.55" x2="188.08" y2="80.73" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="189.97 85.57 193.76 76.35 183.88 77.67 189.97 85.57" style="fill:#1d1d1b"/><line x1="533.72" y1="38.14" x2="576.06" y2="38.14" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="574.6 43.13 583.23 38.15 574.6 33.16 574.6 43.13" style="fill:#1d1d1b"/><line x1="533.72" y1="57.25" x2="576.06" y2="57.25" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="574.6 62.23 583.23 57.25 574.6 52.26 574.6 62.23" style="fill:#1d1d1b"/><line x1="533.72" y1="76.35" x2="576.06" y2="76.35" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="574.6 81.33 583.23 76.35 574.6 71.36 574.6 81.33" style="fill:#1d1d1b"/><line x1="533.72" y1="95.45" x2="576.06" y2="95.45" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="574.6 100.44 583.23 95.45 574.6 90.46 574.6 100.44" style="fill:#1d1d1b"/><line x1="533.72" y1="114.55" x2="576.06" y2="114.55" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="574.6 119.54 583.23 114.55 574.6 109.56 574.6 119.54" style="fill:#1d1d1b"/><rect x="400.47" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="400.47" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="400.47" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="400.47" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="400.47" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="443.27" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="443.27" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="589.72" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="589.72" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="589.72" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="589.72" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="589.72" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="632.52" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="632.52" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><path d="M130.89,145.13a1.9,1.9,0,0,1,.66-1.52,2.71,2.71,0,0,1,1.81-.57h1.79v-.55a1,1,0,0,0-.37-.82,1.59,1.59,0,0,0-1-.29,1.93,1.93,0,0,0-.87.18,1,1,0,0,0-.48.53h-1.3a1.93,1.93,0,0,1,.88-1.31,3.65,3.65,0,0,1,3.77.09,2,2,0,0,1,.73,1.59V147h-1.23v-1.29h-.09a1.57,1.57,0,0,1-.71,1,2.51,2.51,0,0,1-1.41.38,2.17,2.17,0,0,1-1.56-.55A1.89,1.89,0,0,1,130.89,145.13Zm1.32-.11a.94.94,0,0,0,.32.78,1.34,1.34,0,0,0,.91.28,2.17,2.17,0,0,0,.69-.1,1.71,1.71,0,0,0,.54-.27,1.21,1.21,0,0,0,.35-.4,1.14,1.14,0,0,0,.13-.51V144h-1.78a1.21,1.21,0,0,0-.85.28A1,1,0,0,0,132.21,145Z" style="fill:#1d1d1b"/><path d="M137.83,139.49v-1.2h3.46V145a.8.8,0,0,0,.22.61.78.78,0,0,0,.6.23h2V147h-2a2.07,2.07,0,0,1-1.53-.55A2,2,0,0,1,140,145v-5.49Z" style="fill:#1d1d1b"/><path d="M145.68,145.82h2.38V141.6H146v-1.18h3.36v5.4h1.93V147h-5.59Zm1.9-7.22a.71.71,0,0,1,.22-.55.84.84,0,0,1,.59-.21h.29a.8.8,0,0,1,.59.21.78.78,0,0,1,0,1.11.87.87,0,0,1-.6.2h-.28a.88.88,0,0,1-.59-.2A.72.72,0,0,1,147.58,138.6Z" style="fill:#1d1d1b"/><path d="M152.59,142.84a3.5,3.5,0,0,1,.16-1.05,2.22,2.22,0,0,1,.45-.8,2.09,2.09,0,0,1,.73-.51,2.3,2.3,0,0,1,.93-.18,2.1,2.1,0,0,1,1.23.34,1.65,1.65,0,0,1,.63,1h.09v-1.2h1.24v6.2a2.3,2.3,0,0,1-.71,1.78,2.78,2.78,0,0,1-2,.66h-1.71v-1.13h1.71a1.4,1.4,0,0,0,1-.35,1.27,1.27,0,0,0,.36-1v-.23l0-1.2h-.07a1.64,1.64,0,0,1-.65,1,2.07,2.07,0,0,1-1.22.34,2.3,2.3,0,0,1-.93-.18,2,2,0,0,1-.71-.51,2.22,2.22,0,0,1-.45-.8,3.06,3.06,0,0,1-.17-1Zm1.34,1.12a1.41,1.41,0,1,0,2.81,0v-1.11a1.41,1.41,0,1,0-2.81,0Z" style="fill:#1d1d1b"/><path d="M160,140.42h1.25v1.14h.11a1.47,1.47,0,0,1,.58-.94,2.05,2.05,0,0,1,1.18-.32,2.22,2.22,0,0,1,.92.17,1.89,1.89,0,0,1,.68.49,2.13,2.13,0,0,1,.43.75,2.93,2.93,0,0,1,.14,1V147h-1.32v-4.17a1.48,1.48,0,0,0-.34-1,1.27,1.27,0,0,0-1-.38,1.29,1.29,0,0,0-1,.4,1.57,1.57,0,0,0-.36,1.08V147H160Z" style="fill:#1d1d1b"/><path d="M172.45,141v1.2h-5.28V141Zm-5.28,2.93h5.28v1.2h-5.28Z" style="fill:#1d1d1b"/><path d="M173.92,139.56v-1.18h6.19v1.18h-2.42V147h-1.35v-7.46Z" style="fill:#1d1d1b"/><path d="M183.08,140.42v1.14h.11a1.48,1.48,0,0,1,.62-.93,2.43,2.43,0,0,1,2.88.32,2.64,2.64,0,0,1,.59,1.82v.43h-1.35v-.3a1.58,1.58,0,0,0-.37-1.09,1.35,1.35,0,0,0-1-.39,1.33,1.33,0,0,0-1,.4,1.52,1.52,0,0,0-.37,1.08V147h-1.32v-6.6Z" style="fill:#1d1d1b"/><path d="M190.12,140.42v4.18c0,.93.42,1.38,1.28,1.38s1.31-.45,1.31-1.38v-4.18H194v4.18a2.48,2.48,0,0,1-.69,1.88,2.67,2.67,0,0,1-1.94.66,2.63,2.63,0,0,1-1.92-.67,2.46,2.46,0,0,1-.68-1.87v-4.18Z" style="fill:#1d1d1b"/><path d="M195.84,142.85a2.78,2.78,0,0,1,.19-1.06,2.16,2.16,0,0,1,.55-.8,2.55,2.55,0,0,1,.88-.51,3.47,3.47,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.29a2,2,0,0,1-.34.71,2.11,2.11,0,0,1-.6.55,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.41,1.41,0,0,0-.39-1.06,1.43,1.43,0,0,0-1.08-.39,1.33,1.33,0,0,0-1.46,1.45Z" style="fill:#1d1d1b"/><path d="M519.27,145.13a1.88,1.88,0,0,1,.67-1.52,2.66,2.66,0,0,1,1.8-.57h1.79v-.55a1,1,0,0,0-.36-.82,1.61,1.61,0,0,0-1-.29,1.94,1.94,0,0,0-.88.18,1,1,0,0,0-.48.53h-1.29a1.92,1.92,0,0,1,.87-1.31,3.67,3.67,0,0,1,3.78.09,1.94,1.94,0,0,1,.72,1.59V147h-1.22v-1.29h-.1a1.56,1.56,0,0,1-.7,1,2.51,2.51,0,0,1-1.41.38,2.15,2.15,0,0,1-1.56-.55A1.9,1.9,0,0,1,519.27,145.13Zm1.32-.11a1,1,0,0,0,.33.78,1.32,1.32,0,0,0,.91.28,2.07,2.07,0,0,0,.68-.1,1.52,1.52,0,0,0,.54-.27,1.37,1.37,0,0,0,.36-.4,1.13,1.13,0,0,0,.12-.51V144h-1.77a1.24,1.24,0,0,0-.86.28A1,1,0,0,0,520.59,145Z" style="fill:#1d1d1b"/><path d="M526.22,139.49v-1.2h3.46V145a.84.84,0,0,0,.21.61.81.81,0,0,0,.6.23h2V147h-2a2.06,2.06,0,0,1-1.52-.55,2,2,0,0,1-.55-1.49v-5.49Z" style="fill:#1d1d1b"/><path d="M534.07,145.82h2.37V141.6h-2.07v-1.18h3.36v5.4h1.93V147h-5.59ZM536,138.6a.72.72,0,0,1,.23-.55.8.8,0,0,1,.59-.21h.29a.82.82,0,0,1,.59.21.71.71,0,0,1,.22.55.72.72,0,0,1-.22.56.89.89,0,0,1-.6.2h-.28a.84.84,0,0,1-.59-.2A.72.72,0,0,1,536,138.6Z" style="fill:#1d1d1b"/><path d="M541,142.84a3.21,3.21,0,0,1,.16-1.05,2.09,2.09,0,0,1,.45-.8,2.05,2.05,0,0,1,.72-.51,2.35,2.35,0,0,1,.94-.18,2,2,0,0,1,1.22.34,1.62,1.62,0,0,1,.64,1h.08v-1.2h1.25v6.2a2.3,2.3,0,0,1-.71,1.78,2.78,2.78,0,0,1-2,.66h-1.71v-1.13h1.71a1.42,1.42,0,0,0,1-.35,1.27,1.27,0,0,0,.36-1v-.23l0-1.2h-.07a1.68,1.68,0,0,1-.65,1,2.09,2.09,0,0,1-1.22.34,2.27,2.27,0,0,1-.93-.18,1.93,1.93,0,0,1-.71-.51,2.24,2.24,0,0,1-.46-.8,3.07,3.07,0,0,1-.16-1Zm1.33,1.12a1.43,1.43,0,0,0,.38,1,1.41,1.41,0,0,0,2.44-1v-1.11a1.47,1.47,0,0,0-2.44-1,1.43,1.43,0,0,0-.38,1Z" style="fill:#1d1d1b"/><path d="M548.35,140.42h1.25v1.14h.1a1.52,1.52,0,0,1,.59-.94,2.05,2.05,0,0,1,1.18-.32,2.25,2.25,0,0,1,.92.17,2.08,2.08,0,0,1,.68.49,2.13,2.13,0,0,1,.43.75,3.22,3.22,0,0,1,.14,1V147h-1.32v-4.17a1.48,1.48,0,0,0-.35-1,1.24,1.24,0,0,0-1-.38,1.28,1.28,0,0,0-1,.4,1.57,1.57,0,0,0-.36,1.08V147h-1.32Z" style="fill:#1d1d1b"/><path d="M560.84,141v1.2h-5.28V141Zm-5.28,2.93h5.28v1.2h-5.28Z" style="fill:#1d1d1b"/><path d="M562.84,138.37h5.32v1.19h-4V142h3.71v1.2h-3.69V147h-1.32Z" style="fill:#1d1d1b"/><path d="M569.67,145.13a1.88,1.88,0,0,1,.67-1.52,2.66,2.66,0,0,1,1.8-.57h1.79v-.55a1,1,0,0,0-.36-.82,1.61,1.61,0,0,0-1-.29,1.94,1.94,0,0,0-.88.18,1,1,0,0,0-.48.53h-1.29a1.92,1.92,0,0,1,.87-1.31,3.67,3.67,0,0,1,3.78.09,1.94,1.94,0,0,1,.72,1.59V147H574v-1.29h-.1a1.56,1.56,0,0,1-.7,1,2.51,2.51,0,0,1-1.41.38,2.18,2.18,0,0,1-1.57-.55A1.93,1.93,0,0,1,569.67,145.13ZM571,145a1,1,0,0,0,.33.78,1.32,1.32,0,0,0,.91.28,2.11,2.11,0,0,0,.68-.1,1.52,1.52,0,0,0,.54-.27,1.37,1.37,0,0,0,.36-.4,1.13,1.13,0,0,0,.12-.51V144h-1.77a1.24,1.24,0,0,0-.86.28A1,1,0,0,0,571,145Z" style="fill:#1d1d1b"/><path d="M576.62,139.49v-1.2h3.46V145a.84.84,0,0,0,.21.61.81.81,0,0,0,.6.23h2V147h-2a2,2,0,0,1-1.52-.55,2,2,0,0,1-.55-1.49v-5.49Z" style="fill:#1d1d1b"/><path d="M584.19,145.36h1.37a.79.79,0,0,0,.4.52,1.67,1.67,0,0,0,.81.19h.43a1.53,1.53,0,0,0,.92-.24.77.77,0,0,0,.33-.66q0-.72-1.05-.87l-1-.13a2.75,2.75,0,0,1-1.58-.62,1.72,1.72,0,0,1-.51-1.33,1.7,1.7,0,0,1,.64-1.42,2.89,2.89,0,0,1,1.83-.5h.42a2.87,2.87,0,0,1,1.7.46,1.82,1.82,0,0,1,.77,1.25h-1.35a.76.76,0,0,0-.38-.47,1.4,1.4,0,0,0-.74-.17h-.42a1.4,1.4,0,0,0-.86.21.7.7,0,0,0-.3.63.67.67,0,0,0,.22.54,1.39,1.39,0,0,0,.71.25l1,.13a3.08,3.08,0,0,1,1.65.63,2,2,0,0,1-.13,2.86,3,3,0,0,1-1.9.52h-.43a3.08,3.08,0,0,1-1.79-.48A1.77,1.77,0,0,1,584.19,145.36Z" style="fill:#1d1d1b"/><path d="M591.43,142.85a2.78,2.78,0,0,1,.19-1.06,2.16,2.16,0,0,1,.55-.8,2.46,2.46,0,0,1,.88-.51,3.76,3.76,0,0,1,2.3,0,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.44,1.44,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.14,1.14,0,0,0,.54-.47h1.29a2.22,2.22,0,0,1-.94,1.26,2.9,2.9,0,0,1-.8.35,3.79,3.79,0,0,1-1,.12,3.47,3.47,0,0,1-1.15-.18,2.38,2.38,0,0,1-.87-.52,2.2,2.2,0,0,1-.55-.81,2.6,2.6,0,0,1-.2-1.06Zm1.31.25h2.92v-.25a1.41,1.41,0,0,0-.38-1.06,1.69,1.69,0,0,0-2.16,0,1.41,1.41,0,0,0-.38,1.06Z" style="fill:#1d1d1b"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="255.6mm" height="57.81mm" viewBox="0 0 724.53 163.88"><rect x="11" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="11" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="11" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="11" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="11" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="53.8" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="53.8" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="200.25" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="200.25" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="200.25" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="200.25" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="200.25" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="243.05" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="243.05" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="243.05" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><line x1="144.24" y1="38.14" x2="187.07" y2="54.66" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="183.91 58.79 193.76 57.25 187.5 49.49 183.91 58.79" style="fill:#139c5a"/><line x1="144.24" y1="57.25" x2="188.08" y2="91.07" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="183.88 94.12 193.76 95.45 189.97 86.23 183.88 94.12" style="fill:#139c5a"/><line x1="144.24" y1="76.35" x2="188.08" y2="110.17" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="183.88 113.22 193.76 114.55 189.97 105.33 183.88 113.22" style="fill:#139c5a"/><line x1="144.24" y1="95.45" x2="189.07" y2="43.57" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="191.89 47.94 193.76 38.15 184.34 41.42 191.89 47.94" style="fill:#139c5a"/><line x1="144.24" y1="114.55" x2="188.08" y2="80.73" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="189.97 85.57 193.76 76.35 183.88 77.67 189.97 85.57" style="fill:#139c5a"/><line x1="533.72" y1="38.14" x2="576.06" y2="38.14" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="574.6 43.13 583.23 38.15 574.6 33.16 574.6 43.13" style="fill:#139c5a"/><line x1="533.72" y1="57.25" x2="576.06" y2="57.25" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="574.6 62.23 583.23 57.25 574.6 52.26 574.6 62.23" style="fill:#139c5a"/><line x1="533.72" y1="76.35" x2="576.06" y2="76.35" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="574.6 81.33 583.23 76.35 574.6 71.36 574.6 81.33" style="fill:#139c5a"/><line x1="533.72" y1="95.45" x2="576.06" y2="95.45" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="574.6 100.44 583.23 95.45 574.6 90.46 574.6 100.44" style="fill:#139c5a"/><line x1="533.72" y1="114.55" x2="576.06" y2="114.55" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="574.6 119.54 583.23 114.55 574.6 109.56 574.6 119.54" style="fill:#139c5a"/><rect x="400.47" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="400.47" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="400.47" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="400.47" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="400.47" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="443.27" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="443.27" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="443.27" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="589.72" y="28.59" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="589.72" y="47.7" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="589.72" y="66.8" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="589.72" y="85.9" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="589.72" y="105" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="632.52" y="28.59" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="9.49" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="632.52" y="47.7" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="66.8" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="85.9" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="632.52" y="105" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><path d="M130.89,145.13a1.9,1.9,0,0,1,.66-1.52,2.71,2.71,0,0,1,1.81-.57h1.79v-.55a1,1,0,0,0-.37-.82,1.59,1.59,0,0,0-1-.29,1.93,1.93,0,0,0-.87.18,1,1,0,0,0-.48.53h-1.3a1.93,1.93,0,0,1,.88-1.31,3.65,3.65,0,0,1,3.77.09,2,2,0,0,1,.73,1.59V147h-1.23v-1.29h-.09a1.57,1.57,0,0,1-.71,1,2.51,2.51,0,0,1-1.41.38,2.17,2.17,0,0,1-1.56-.55A1.89,1.89,0,0,1,130.89,145.13Zm1.32-.11a.94.94,0,0,0,.32.78,1.34,1.34,0,0,0,.91.28,2.17,2.17,0,0,0,.69-.1,1.71,1.71,0,0,0,.54-.27,1.21,1.21,0,0,0,.35-.4,1.14,1.14,0,0,0,.13-.51V144h-1.78a1.21,1.21,0,0,0-.85.28A1,1,0,0,0,132.21,145Z" style="fill:#139c5a"/><path d="M137.83,139.49v-1.2h3.46V145a.8.8,0,0,0,.22.61.78.78,0,0,0,.6.23h2V147h-2a2.07,2.07,0,0,1-1.53-.55A2,2,0,0,1,140,145v-5.49Z" style="fill:#139c5a"/><path d="M145.68,145.82h2.38V141.6H146v-1.18h3.36v5.4h1.93V147h-5.59Zm1.9-7.22a.71.71,0,0,1,.22-.55.84.84,0,0,1,.59-.21h.29a.8.8,0,0,1,.59.21.78.78,0,0,1,0,1.11.87.87,0,0,1-.6.2h-.28a.88.88,0,0,1-.59-.2A.72.72,0,0,1,147.58,138.6Z" style="fill:#139c5a"/><path d="M152.59,142.84a3.5,3.5,0,0,1,.16-1.05,2.22,2.22,0,0,1,.45-.8,2.09,2.09,0,0,1,.73-.51,2.3,2.3,0,0,1,.93-.18,2.1,2.1,0,0,1,1.23.34,1.65,1.65,0,0,1,.63,1h.09v-1.2h1.24v6.2a2.3,2.3,0,0,1-.71,1.78,2.78,2.78,0,0,1-2,.66h-1.71v-1.13h1.71a1.4,1.4,0,0,0,1-.35,1.27,1.27,0,0,0,.36-1v-.23l0-1.2h-.07a1.64,1.64,0,0,1-.65,1,2.07,2.07,0,0,1-1.22.34,2.3,2.3,0,0,1-.93-.18,2,2,0,0,1-.71-.51,2.22,2.22,0,0,1-.45-.8,3.06,3.06,0,0,1-.17-1Zm1.34,1.12a1.41,1.41,0,1,0,2.81,0v-1.11a1.41,1.41,0,1,0-2.81,0Z" style="fill:#139c5a"/><path d="M160,140.42h1.25v1.14h.11a1.47,1.47,0,0,1,.58-.94,2.05,2.05,0,0,1,1.18-.32,2.22,2.22,0,0,1,.92.17,1.89,1.89,0,0,1,.68.49,2.13,2.13,0,0,1,.43.75,2.93,2.93,0,0,1,.14,1V147h-1.32v-4.17a1.48,1.48,0,0,0-.34-1,1.27,1.27,0,0,0-1-.38,1.29,1.29,0,0,0-1,.4,1.57,1.57,0,0,0-.36,1.08V147H160Z" style="fill:#139c5a"/><path d="M172.45,141v1.2h-5.28V141Zm-5.28,2.93h5.28v1.2h-5.28Z" style="fill:#139c5a"/><path d="M173.92,139.56v-1.18h6.19v1.18h-2.42V147h-1.35v-7.46Z" style="fill:#139c5a"/><path d="M183.08,140.42v1.14h.11a1.48,1.48,0,0,1,.62-.93,2.43,2.43,0,0,1,2.88.32,2.64,2.64,0,0,1,.59,1.82v.43h-1.35v-.3a1.58,1.58,0,0,0-.37-1.09,1.35,1.35,0,0,0-1-.39,1.33,1.33,0,0,0-1,.4,1.52,1.52,0,0,0-.37,1.08V147h-1.32v-6.6Z" style="fill:#139c5a"/><path d="M190.12,140.42v4.18c0,.93.42,1.38,1.28,1.38s1.31-.45,1.31-1.38v-4.18H194v4.18a2.48,2.48,0,0,1-.69,1.88,2.67,2.67,0,0,1-1.94.66,2.63,2.63,0,0,1-1.92-.67,2.46,2.46,0,0,1-.68-1.87v-4.18Z" style="fill:#139c5a"/><path d="M195.84,142.85a2.78,2.78,0,0,1,.19-1.06,2.16,2.16,0,0,1,.55-.8,2.55,2.55,0,0,1,.88-.51,3.47,3.47,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.29a2,2,0,0,1-.34.71,2.11,2.11,0,0,1-.6.55,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.38,2.38,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.41,1.41,0,0,0-.39-1.06,1.43,1.43,0,0,0-1.08-.39,1.33,1.33,0,0,0-1.46,1.45Z" style="fill:#139c5a"/><path d="M519.27,145.13a1.88,1.88,0,0,1,.67-1.52,2.66,2.66,0,0,1,1.8-.57h1.79v-.55a1,1,0,0,0-.36-.82,1.61,1.61,0,0,0-1-.29,1.94,1.94,0,0,0-.88.18,1,1,0,0,0-.48.53h-1.29a1.92,1.92,0,0,1,.87-1.31,3.67,3.67,0,0,1,3.78.09,1.94,1.94,0,0,1,.72,1.59V147h-1.22v-1.29h-.1a1.56,1.56,0,0,1-.7,1,2.51,2.51,0,0,1-1.41.38,2.15,2.15,0,0,1-1.56-.55A1.9,1.9,0,0,1,519.27,145.13Zm1.32-.11a1,1,0,0,0,.33.78,1.32,1.32,0,0,0,.91.28,2.07,2.07,0,0,0,.68-.1,1.52,1.52,0,0,0,.54-.27,1.37,1.37,0,0,0,.36-.4,1.13,1.13,0,0,0,.12-.51V144h-1.77a1.24,1.24,0,0,0-.86.28A1,1,0,0,0,520.59,145Z" style="fill:#139c5a"/><path d="M526.22,139.49v-1.2h3.46V145a.84.84,0,0,0,.21.61.81.81,0,0,0,.6.23h2V147h-2a2.06,2.06,0,0,1-1.52-.55,2,2,0,0,1-.55-1.49v-5.49Z" style="fill:#139c5a"/><path d="M534.07,145.82h2.37V141.6h-2.07v-1.18h3.36v5.4h1.93V147h-5.59ZM536,138.6a.72.72,0,0,1,.23-.55.8.8,0,0,1,.59-.21h.29a.82.82,0,0,1,.59.21.71.71,0,0,1,.22.55.72.72,0,0,1-.22.56.89.89,0,0,1-.6.2h-.28a.84.84,0,0,1-.59-.2A.72.72,0,0,1,536,138.6Z" style="fill:#139c5a"/><path d="M541,142.84a3.21,3.21,0,0,1,.16-1.05,2.09,2.09,0,0,1,.45-.8,2.05,2.05,0,0,1,.72-.51,2.35,2.35,0,0,1,.94-.18,2,2,0,0,1,1.22.34,1.62,1.62,0,0,1,.64,1h.08v-1.2h1.25v6.2a2.3,2.3,0,0,1-.71,1.78,2.78,2.78,0,0,1-2,.66h-1.71v-1.13h1.71a1.42,1.42,0,0,0,1-.35,1.27,1.27,0,0,0,.36-1v-.23l0-1.2h-.07a1.68,1.68,0,0,1-.65,1,2.09,2.09,0,0,1-1.22.34,2.27,2.27,0,0,1-.93-.18,1.93,1.93,0,0,1-.71-.51,2.24,2.24,0,0,1-.46-.8,3.07,3.07,0,0,1-.16-1Zm1.33,1.12a1.43,1.43,0,0,0,.38,1,1.41,1.41,0,0,0,2.44-1v-1.11a1.47,1.47,0,0,0-2.44-1,1.43,1.43,0,0,0-.38,1Z" style="fill:#139c5a"/><path d="M548.35,140.42h1.25v1.14h.1a1.52,1.52,0,0,1,.59-.94,2.05,2.05,0,0,1,1.18-.32,2.25,2.25,0,0,1,.92.17,2.08,2.08,0,0,1,.68.49,2.13,2.13,0,0,1,.43.75,3.22,3.22,0,0,1,.14,1V147h-1.32v-4.17a1.48,1.48,0,0,0-.35-1,1.24,1.24,0,0,0-1-.38,1.28,1.28,0,0,0-1,.4,1.57,1.57,0,0,0-.36,1.08V147h-1.32Z" style="fill:#139c5a"/><path d="M560.84,141v1.2h-5.28V141Zm-5.28,2.93h5.28v1.2h-5.28Z" style="fill:#139c5a"/><path d="M562.84,138.37h5.32v1.19h-4V142h3.71v1.2h-3.69V147h-1.32Z" style="fill:#139c5a"/><path d="M569.67,145.13a1.88,1.88,0,0,1,.67-1.52,2.66,2.66,0,0,1,1.8-.57h1.79v-.55a1,1,0,0,0-.36-.82,1.61,1.61,0,0,0-1-.29,1.94,1.94,0,0,0-.88.18,1,1,0,0,0-.48.53h-1.29a1.92,1.92,0,0,1,.87-1.31,3.67,3.67,0,0,1,3.78.09,1.94,1.94,0,0,1,.72,1.59V147H574v-1.29h-.1a1.56,1.56,0,0,1-.7,1,2.51,2.51,0,0,1-1.41.38,2.18,2.18,0,0,1-1.57-.55A1.93,1.93,0,0,1,569.67,145.13ZM571,145a1,1,0,0,0,.33.78,1.32,1.32,0,0,0,.91.28,2.11,2.11,0,0,0,.68-.1,1.52,1.52,0,0,0,.54-.27,1.37,1.37,0,0,0,.36-.4,1.13,1.13,0,0,0,.12-.51V144h-1.77a1.24,1.24,0,0,0-.86.28A1,1,0,0,0,571,145Z" style="fill:#139c5a"/><path d="M576.62,139.49v-1.2h3.46V145a.84.84,0,0,0,.21.61.81.81,0,0,0,.6.23h2V147h-2a2,2,0,0,1-1.52-.55,2,2,0,0,1-.55-1.49v-5.49Z" style="fill:#139c5a"/><path d="M584.19,145.36h1.37a.79.79,0,0,0,.4.52,1.67,1.67,0,0,0,.81.19h.43a1.53,1.53,0,0,0,.92-.24.77.77,0,0,0,.33-.66q0-.72-1.05-.87l-1-.13a2.75,2.75,0,0,1-1.58-.62,1.72,1.72,0,0,1-.51-1.33,1.7,1.7,0,0,1,.64-1.42,2.89,2.89,0,0,1,1.83-.5h.42a2.87,2.87,0,0,1,1.7.46,1.82,1.82,0,0,1,.77,1.25h-1.35a.76.76,0,0,0-.38-.47,1.4,1.4,0,0,0-.74-.17h-.42a1.4,1.4,0,0,0-.86.21.7.7,0,0,0-.3.63.67.67,0,0,0,.22.54,1.39,1.39,0,0,0,.71.25l1,.13a3.08,3.08,0,0,1,1.65.63,2,2,0,0,1-.13,2.86,3,3,0,0,1-1.9.52h-.43a3.08,3.08,0,0,1-1.79-.48A1.77,1.77,0,0,1,584.19,145.36Z" style="fill:#139c5a"/><path d="M591.43,142.85a2.78,2.78,0,0,1,.19-1.06,2.16,2.16,0,0,1,.55-.8,2.46,2.46,0,0,1,.88-.51,3.76,3.76,0,0,1,2.3,0,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.44,1.44,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.14,1.14,0,0,0,.54-.47h1.29a2.22,2.22,0,0,1-.94,1.26,2.9,2.9,0,0,1-.8.35,3.79,3.79,0,0,1-1,.12,3.47,3.47,0,0,1-1.15-.18,2.38,2.38,0,0,1-.87-.52,2.2,2.2,0,0,1-.55-.81,2.6,2.6,0,0,1-.2-1.06Zm1.31.25h2.92v-.25a1.41,1.41,0,0,0-.38-1.06,1.69,1.69,0,0,0-2.16,0,1.41,1.41,0,0,0-.38,1.06Z" style="fill:#139c5a"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="107.81mm" height="51.72mm" viewBox="0 0 305.59 146.59"><path d="M209,116.05h1.36a.81.81,0,0,0,.41.52,1.67,1.67,0,0,0,.81.19H212a1.55,1.55,0,0,0,.92-.24.77.77,0,0,0,.33-.66c0-.48-.36-.77-1.06-.87l-1-.13a2.78,2.78,0,0,1-1.58-.62,1.94,1.94,0,0,1,.13-2.75,2.89,2.89,0,0,1,1.83-.5h.42a2.85,2.85,0,0,1,1.7.46,1.79,1.79,0,0,1,.78,1.25h-1.36a.72.72,0,0,0-.37-.47,1.44,1.44,0,0,0-.75-.18h-.42a1.5,1.5,0,0,0-.86.21.72.72,0,0,0-.3.63.65.65,0,0,0,.22.54,1.34,1.34,0,0,0,.72.26l1,.13a3.08,3.08,0,0,1,1.66.63,2,2,0,0,1-.14,2.85,3,3,0,0,1-1.89.53h-.43a3.09,3.09,0,0,1-1.8-.48A1.73,1.73,0,0,1,209,116.05Z" style="fill:#1d1d1b"/><path d="M216.36,117.71v-8.64h1.32v2c0,.11,0,.23,0,.36s0,.26,0,.37,0,.25,0,.41h.11a1.49,1.49,0,0,1,.59-.93,2,2,0,0,1,1.17-.33,2.36,2.36,0,0,1,.9.16,2.2,2.2,0,0,1,.68.48,2.32,2.32,0,0,1,.44.75,3.05,3.05,0,0,1,.15,1v4.35h-1.3v-4.17a1.45,1.45,0,0,0-.36-1.05,1.26,1.26,0,0,0-1-.38,1.29,1.29,0,0,0-1,.4,1.53,1.53,0,0,0-.36,1.08v4.12Z" style="fill:#1d1d1b"/><path d="M223.29,115.82a1.88,1.88,0,0,1,.66-1.52,2.71,2.71,0,0,1,1.81-.57h1.79v-.55a1,1,0,0,0-.37-.82,1.59,1.59,0,0,0-1-.29,1.93,1.93,0,0,0-.87.18,1,1,0,0,0-.48.52h-1.3a1.93,1.93,0,0,1,.88-1.3,3.65,3.65,0,0,1,3.77.09,1.93,1.93,0,0,1,.73,1.59v4.56h-1.23v-1.29h-.09a1.59,1.59,0,0,1-.71,1,2.51,2.51,0,0,1-1.41.38,2.21,2.21,0,0,1-1.56-.55A1.89,1.89,0,0,1,223.29,115.82Zm1.32-.11a.94.94,0,0,0,.32.78,1.34,1.34,0,0,0,.91.28,2.17,2.17,0,0,0,.69-.1,1.71,1.71,0,0,0,.54-.27,1.21,1.21,0,0,0,.35-.4,1.14,1.14,0,0,0,.13-.51v-.83h-1.78a1.26,1.26,0,0,0-.85.27A1,1,0,0,0,224.61,115.71Z" style="fill:#1d1d1b"/><path d="M230.77,111.11H232v1.14h.1a1.47,1.47,0,0,1,.61-.93,2,2,0,0,1,1.19-.33,2.29,2.29,0,0,1,.92.18,2.05,2.05,0,0,1,.72.51,2.46,2.46,0,0,1,.45.81,3.31,3.31,0,0,1,.17,1.08v1.65a3.41,3.41,0,0,1-.17,1.09,2.32,2.32,0,0,1-.45.82,2.08,2.08,0,0,1-.72.52,2.29,2.29,0,0,1-.92.18,2,2,0,0,1-1.19-.33,1.47,1.47,0,0,1-.61-.93H232s0,.05,0,.13,0,.17,0,.29,0,.23,0,.36,0,.24,0,.36v2h-1.32Zm1.32,2.48v1.63a1.54,1.54,0,0,0,.37,1.06,1.28,1.28,0,0,0,1,.39,1.38,1.38,0,0,0,1-.39,1.5,1.5,0,0,0,.38-1.07v-1.62a1.47,1.47,0,0,0-.38-1.07,1.38,1.38,0,0,0-1-.39,1.27,1.27,0,0,0-1,.39A1.5,1.5,0,0,0,232.09,113.59Z" style="fill:#1d1d1b"/><path d="M237.84,113.54a3,3,0,0,1,.19-1.06,2.18,2.18,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.3a2.18,2.18,0,0,1-1,1.26,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.52,2.52,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.34,1.34,0,0,0-1.47-1.45,1.32,1.32,0,0,0-1.46,1.45Z" style="fill:#1d1d1b"/><path d="M244.63,110.18V109h3.46v6.69a.8.8,0,0,0,.22.61.78.78,0,0,0,.6.23h2v1.2h-2a2.11,2.11,0,0,1-1.53-.55,2,2,0,0,1-.55-1.49v-5.49Z" style="fill:#1d1d1b"/><path d="M251.92,111.11h1.44l1.39,3.63a4.42,4.42,0,0,1,.15.48,4.15,4.15,0,0,1,.09.43c0,.16,0,.3.06.44h.1a3.59,3.59,0,0,1,0-.44c0-.12.06-.27.09-.43s.09-.32.14-.48l1.3-3.63h1.39l-3.17,8.64h-1.39l.91-2.46Z" style="fill:#1d1d1b"/><path d="M205.39,127.93a3.5,3.5,0,0,1,.16-1.05,2.1,2.1,0,0,1,.46-.8,2.05,2.05,0,0,1,.72-.51,2.34,2.34,0,0,1,.93-.18,2.1,2.1,0,0,1,1.23.34,1.61,1.61,0,0,1,.63,1h.09v-1.2h1.24v6.2a2.27,2.27,0,0,1-.71,1.78,2.78,2.78,0,0,1-2,.66h-1.71V133h1.71a1.4,1.4,0,0,0,1-.35,1.27,1.27,0,0,0,.37-1v-.23l0-1.2h-.07a1.59,1.59,0,0,1-.65,1,2,2,0,0,1-1.22.35,2.34,2.34,0,0,1-.93-.18,2,2,0,0,1-.71-.51,2.22,2.22,0,0,1-.45-.8,3.11,3.11,0,0,1-.17-1Zm1.34,1.12a1.41,1.41,0,1,0,2.82,0v-1.11a1.43,1.43,0,0,0-.38-1,1.63,1.63,0,0,0-2.07,0,1.42,1.42,0,0,0-.37,1Z" style="fill:#1d1d1b"/><path d="M212.64,127.94a3,3,0,0,1,.19-1.06,2.18,2.18,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21H214v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.3a2.18,2.18,0,0,1-.95,1.26,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.52,2.52,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.34,1.34,0,0,0-1.47-1.45,1.32,1.32,0,0,0-1.46,1.45Z" style="fill:#1d1d1b"/><path d="M222.61,132.23a3.41,3.41,0,0,1-1.14-.19,2.4,2.4,0,0,1-.87-.53,2.35,2.35,0,0,1-.56-.82,2.83,2.83,0,0,1-.2-1.07V128a2.83,2.83,0,0,1,.2-1.07,2.35,2.35,0,0,1,.56-.82,2.4,2.4,0,0,1,.87-.53,3.64,3.64,0,0,1,2.29,0,2.4,2.4,0,0,1,.87.53,2.31,2.31,0,0,1,.56.81,2.85,2.85,0,0,1,.2,1.08v1.65a2.92,2.92,0,0,1-.2,1.08,2.32,2.32,0,0,1-.55.82,2.52,2.52,0,0,1-.87.52A3.53,3.53,0,0,1,222.61,132.23Zm-1.45-2.61a1.43,1.43,0,0,0,.39,1.06,1.45,1.45,0,0,0,1.06.38,1.49,1.49,0,0,0,1.07-.38,1.42,1.42,0,0,0,.38-1.06V128a1.42,1.42,0,0,0-.38-1.06,1.68,1.68,0,0,0-2.13,0,1.43,1.43,0,0,0-.39,1.06Z" style="fill:#1d1d1b"/><path d="M226.87,132.11v-6.6H228v1h.09a1.27,1.27,0,0,1,.32-.81,1,1,0,0,1,.76-.28.94.94,0,0,1,.72.27,1.7,1.7,0,0,1,.39.82h.08a1.22,1.22,0,0,1,.32-.81,1.08,1.08,0,0,1,.78-.28,1.2,1.2,0,0,1,1,.45,1.93,1.93,0,0,1,.37,1.24v5h-1.22v-5a1,1,0,0,0-.15-.59.54.54,0,0,0-.46-.2q-.63,0-.63.84v4.92h-1v-5a.92.92,0,0,0-.16-.59.59.59,0,0,0-.48-.2q-.63,0-.63.84v4.92Z" style="fill:#1d1d1b"/><path d="M234.24,127.94a3,3,0,0,1,.19-1.06,2.18,2.18,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.3a2.18,2.18,0,0,1-.95,1.26,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.52,2.52,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.34,1.34,0,0,0-1.47-1.45,1.32,1.32,0,0,0-1.46,1.45Z" style="fill:#1d1d1b"/><path d="M241.24,125.51h1.86v-2h1.32v2H247v1.18h-2.53v3.52a.66.66,0,0,0,.19.51.77.77,0,0,0,.54.19h1.68v1.2h-1.74a2,2,0,0,1-1.46-.52,1.8,1.8,0,0,1-.53-1.38v-3.52h-1.86Z" style="fill:#1d1d1b"/><path d="M250.28,125.51v1.14h.11a1.48,1.48,0,0,1,.62-.93,2.43,2.43,0,0,1,2.88.32,2.64,2.64,0,0,1,.59,1.82v.43h-1.35V128a1.56,1.56,0,0,0-.37-1.09,1.35,1.35,0,0,0-1-.39,1.33,1.33,0,0,0-1,.4,1.49,1.49,0,0,0-.37,1.08v4.12H249v-6.6Z" style="fill:#1d1d1b"/><path d="M255.52,125.51H257l1.39,3.63a4.42,4.42,0,0,1,.15.48c0,.15.06.3.09.43s0,.3.06.44h.1a3.59,3.59,0,0,1,0-.44c0-.12.06-.27.09-.43s.09-.32.14-.48l1.3-3.63h1.39l-3.17,8.64h-1.39l.91-2.46Z" style="fill:#1d1d1b"/><rect x="11" y="31.75" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="11" y="50.85" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="11" y="69.95" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="11" y="89.05" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="11" y="108.16" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="53.8" y="31.75" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="12.65" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="53.8" y="50.85" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="69.95" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="89.05" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="108.16" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><line x1="144.24" y1="41.3" x2="193.76" y2="79.5" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><line x1="144.24" y1="60.4" x2="193.76" y2="79.5" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><line x1="144.24" y1="79.5" x2="193.76" y2="79.5" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="192.3 84.49 200.94 79.5 192.3 74.52 192.3 84.49" style="fill:#1d1d1b"/><line x1="144.24" y1="98.6" x2="193.76" y2="79.5" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><line x1="144.24" y1="117.71" x2="193.76" y2="79.5" style="fill:none;stroke:#1d1d1b;stroke-miterlimit:10"/><polygon points="254.5 75.67 247.28 95.85 226.19 99.69 212.32 83.34 219.55 63.16 240.64 59.32 254.5 75.67" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/></svg>
0 <svg xmlns="http://www.w3.org/2000/svg" width="107.81mm" height="51.72mm" viewBox="0 0 305.59 146.59"><path d="M209,116.05h1.36a.81.81,0,0,0,.41.52,1.67,1.67,0,0,0,.81.19H212a1.55,1.55,0,0,0,.92-.24.77.77,0,0,0,.33-.66c0-.48-.36-.77-1.06-.87l-1-.13a2.78,2.78,0,0,1-1.58-.62,1.94,1.94,0,0,1,.13-2.75,2.89,2.89,0,0,1,1.83-.5h.42a2.85,2.85,0,0,1,1.7.46,1.79,1.79,0,0,1,.78,1.25h-1.36a.72.72,0,0,0-.37-.47,1.44,1.44,0,0,0-.75-.18h-.42a1.5,1.5,0,0,0-.86.21.72.72,0,0,0-.3.63.65.65,0,0,0,.22.54,1.34,1.34,0,0,0,.72.26l1,.13a3.08,3.08,0,0,1,1.66.63,2,2,0,0,1-.14,2.85,3,3,0,0,1-1.89.53h-.43a3.09,3.09,0,0,1-1.8-.48A1.73,1.73,0,0,1,209,116.05Z" style="fill:#139c5a"/><path d="M216.36,117.71v-8.64h1.32v2c0,.11,0,.23,0,.36s0,.26,0,.37,0,.25,0,.41h.11a1.49,1.49,0,0,1,.59-.93,2,2,0,0,1,1.17-.33,2.36,2.36,0,0,1,.9.16,2.2,2.2,0,0,1,.68.48,2.32,2.32,0,0,1,.44.75,3.05,3.05,0,0,1,.15,1v4.35h-1.3v-4.17a1.45,1.45,0,0,0-.36-1.05,1.26,1.26,0,0,0-1-.38,1.29,1.29,0,0,0-1,.4,1.53,1.53,0,0,0-.36,1.08v4.12Z" style="fill:#139c5a"/><path d="M223.29,115.82a1.88,1.88,0,0,1,.66-1.52,2.71,2.71,0,0,1,1.81-.57h1.79v-.55a1,1,0,0,0-.37-.82,1.59,1.59,0,0,0-1-.29,1.93,1.93,0,0,0-.87.18,1,1,0,0,0-.48.52h-1.3a1.93,1.93,0,0,1,.88-1.3,3.65,3.65,0,0,1,3.77.09,1.93,1.93,0,0,1,.73,1.59v4.56h-1.23v-1.29h-.09a1.59,1.59,0,0,1-.71,1,2.51,2.51,0,0,1-1.41.38,2.21,2.21,0,0,1-1.56-.55A1.89,1.89,0,0,1,223.29,115.82Zm1.32-.11a.94.94,0,0,0,.32.78,1.34,1.34,0,0,0,.91.28,2.17,2.17,0,0,0,.69-.1,1.71,1.71,0,0,0,.54-.27,1.21,1.21,0,0,0,.35-.4,1.14,1.14,0,0,0,.13-.51v-.83h-1.78a1.26,1.26,0,0,0-.85.27A1,1,0,0,0,224.61,115.71Z" style="fill:#139c5a"/><path d="M230.77,111.11H232v1.14h.1a1.47,1.47,0,0,1,.61-.93,2,2,0,0,1,1.19-.33,2.29,2.29,0,0,1,.92.18,2.05,2.05,0,0,1,.72.51,2.46,2.46,0,0,1,.45.81,3.31,3.31,0,0,1,.17,1.08v1.65a3.41,3.41,0,0,1-.17,1.09,2.32,2.32,0,0,1-.45.82,2.08,2.08,0,0,1-.72.52,2.29,2.29,0,0,1-.92.18,2,2,0,0,1-1.19-.33,1.47,1.47,0,0,1-.61-.93H232s0,.05,0,.13,0,.17,0,.29,0,.23,0,.36,0,.24,0,.36v2h-1.32Zm1.32,2.48v1.63a1.54,1.54,0,0,0,.37,1.06,1.28,1.28,0,0,0,1,.39,1.38,1.38,0,0,0,1-.39,1.5,1.5,0,0,0,.38-1.07v-1.62a1.47,1.47,0,0,0-.38-1.07,1.38,1.38,0,0,0-1-.39,1.27,1.27,0,0,0-1,.39A1.5,1.5,0,0,0,232.09,113.59Z" style="fill:#139c5a"/><path d="M237.84,113.54a3,3,0,0,1,.19-1.06,2.18,2.18,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.3a2.18,2.18,0,0,1-1,1.26,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.52,2.52,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.34,1.34,0,0,0-1.47-1.45,1.32,1.32,0,0,0-1.46,1.45Z" style="fill:#139c5a"/><path d="M244.63,110.18V109h3.46v6.69a.8.8,0,0,0,.22.61.78.78,0,0,0,.6.23h2v1.2h-2a2.11,2.11,0,0,1-1.53-.55,2,2,0,0,1-.55-1.49v-5.49Z" style="fill:#139c5a"/><path d="M251.92,111.11h1.44l1.39,3.63a4.42,4.42,0,0,1,.15.48,4.15,4.15,0,0,1,.09.43c0,.16,0,.3.06.44h.1a3.59,3.59,0,0,1,0-.44c0-.12.06-.27.09-.43s.09-.32.14-.48l1.3-3.63h1.39l-3.17,8.64h-1.39l.91-2.46Z" style="fill:#139c5a"/><path d="M205.39,127.93a3.5,3.5,0,0,1,.16-1.05,2.1,2.1,0,0,1,.46-.8,2.05,2.05,0,0,1,.72-.51,2.34,2.34,0,0,1,.93-.18,2.1,2.1,0,0,1,1.23.34,1.61,1.61,0,0,1,.63,1h.09v-1.2h1.24v6.2a2.27,2.27,0,0,1-.71,1.78,2.78,2.78,0,0,1-2,.66h-1.71V133h1.71a1.4,1.4,0,0,0,1-.35,1.27,1.27,0,0,0,.37-1v-.23l0-1.2h-.07a1.59,1.59,0,0,1-.65,1,2,2,0,0,1-1.22.35,2.34,2.34,0,0,1-.93-.18,2,2,0,0,1-.71-.51,2.22,2.22,0,0,1-.45-.8,3.11,3.11,0,0,1-.17-1Zm1.34,1.12a1.41,1.41,0,1,0,2.82,0v-1.11a1.43,1.43,0,0,0-.38-1,1.63,1.63,0,0,0-2.07,0,1.42,1.42,0,0,0-.37,1Z" style="fill:#139c5a"/><path d="M212.64,127.94a3,3,0,0,1,.19-1.06,2.18,2.18,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21H214v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.3a2.18,2.18,0,0,1-.95,1.26,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.52,2.52,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.34,1.34,0,0,0-1.47-1.45,1.32,1.32,0,0,0-1.46,1.45Z" style="fill:#139c5a"/><path d="M222.61,132.23a3.41,3.41,0,0,1-1.14-.19,2.4,2.4,0,0,1-.87-.53,2.35,2.35,0,0,1-.56-.82,2.83,2.83,0,0,1-.2-1.07V128a2.83,2.83,0,0,1,.2-1.07,2.35,2.35,0,0,1,.56-.82,2.4,2.4,0,0,1,.87-.53,3.64,3.64,0,0,1,2.29,0,2.4,2.4,0,0,1,.87.53,2.31,2.31,0,0,1,.56.81,2.85,2.85,0,0,1,.2,1.08v1.65a2.92,2.92,0,0,1-.2,1.08,2.32,2.32,0,0,1-.55.82,2.52,2.52,0,0,1-.87.52A3.53,3.53,0,0,1,222.61,132.23Zm-1.45-2.61a1.43,1.43,0,0,0,.39,1.06,1.45,1.45,0,0,0,1.06.38,1.49,1.49,0,0,0,1.07-.38,1.42,1.42,0,0,0,.38-1.06V128a1.42,1.42,0,0,0-.38-1.06,1.68,1.68,0,0,0-2.13,0,1.43,1.43,0,0,0-.39,1.06Z" style="fill:#139c5a"/><path d="M226.87,132.11v-6.6H228v1h.09a1.27,1.27,0,0,1,.32-.81,1,1,0,0,1,.76-.28.94.94,0,0,1,.72.27,1.7,1.7,0,0,1,.39.82h.08a1.22,1.22,0,0,1,.32-.81,1.08,1.08,0,0,1,.78-.28,1.2,1.2,0,0,1,1,.45,1.93,1.93,0,0,1,.37,1.24v5h-1.22v-5a1,1,0,0,0-.15-.59.54.54,0,0,0-.46-.2q-.63,0-.63.84v4.92h-1v-5a.92.92,0,0,0-.16-.59.59.59,0,0,0-.48-.2q-.63,0-.63.84v4.92Z" style="fill:#139c5a"/><path d="M234.24,127.94a3,3,0,0,1,.19-1.06,2.18,2.18,0,0,1,.56-.8,2.5,2.5,0,0,1,.87-.51,3.51,3.51,0,0,1,1.15-.18,3.43,3.43,0,0,1,1.15.18,2.5,2.5,0,0,1,.87.51,2.16,2.16,0,0,1,.55.8,2.78,2.78,0,0,1,.19,1.06v1.21h-4.22v.47a1.53,1.53,0,0,0,.39,1.11,1.45,1.45,0,0,0,1.07.39,2.35,2.35,0,0,0,.88-.15,1.05,1.05,0,0,0,.54-.47h1.3a2.18,2.18,0,0,1-.95,1.26,2.77,2.77,0,0,1-.8.35,3.74,3.74,0,0,1-1,.12,3.41,3.41,0,0,1-1.14-.18,2.52,2.52,0,0,1-.87-.52,2.22,2.22,0,0,1-.56-.81,2.78,2.78,0,0,1-.2-1.06Zm1.31.25h2.93v-.25a1.34,1.34,0,0,0-1.47-1.45,1.32,1.32,0,0,0-1.46,1.45Z" style="fill:#139c5a"/><path d="M241.24,125.51h1.86v-2h1.32v2H247v1.18h-2.53v3.52a.66.66,0,0,0,.19.51.77.77,0,0,0,.54.19h1.68v1.2h-1.74a2,2,0,0,1-1.46-.52,1.8,1.8,0,0,1-.53-1.38v-3.52h-1.86Z" style="fill:#139c5a"/><path d="M250.28,125.51v1.14h.11a1.48,1.48,0,0,1,.62-.93,2.43,2.43,0,0,1,2.88.32,2.64,2.64,0,0,1,.59,1.82v.43h-1.35V128a1.56,1.56,0,0,0-.37-1.09,1.35,1.35,0,0,0-1-.39,1.33,1.33,0,0,0-1,.4,1.49,1.49,0,0,0-.37,1.08v4.12H249v-6.6Z" style="fill:#139c5a"/><path d="M255.52,125.51H257l1.39,3.63a4.42,4.42,0,0,1,.15.48c0,.15.06.3.09.43s0,.3.06.44h.1a3.59,3.59,0,0,1,0-.44c0-.12.06-.27.09-.43s.09-.32.14-.48l1.3-3.63h1.39l-3.17,8.64h-1.39l.91-2.46Z" style="fill:#139c5a"/><rect x="11" y="31.75" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="11" y="50.85" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="11" y="69.95" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.6"/><rect x="11" y="89.05" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10;opacity:0.8"/><rect x="11" y="108.16" width="38.2" height="19.1" style="fill:#0f9c5a;stroke:#fff;stroke-miterlimit:10"/><rect x="53.8" y="31.75" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="12.65" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.4"/><rect x="53.8" y="50.85" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="69.95" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="89.05" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><rect x="53.8" y="108.16" width="83.41" height="19.1" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/><line x1="144.24" y1="41.3" x2="193.76" y2="79.5" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><line x1="144.24" y1="60.4" x2="193.76" y2="79.5" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><line x1="144.24" y1="79.5" x2="193.76" y2="79.5" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="192.3 84.49 200.94 79.5 192.3 74.52 192.3 84.49" style="fill:#139c5a"/><line x1="144.24" y1="98.6" x2="193.76" y2="79.5" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><line x1="144.24" y1="117.71" x2="193.76" y2="79.5" style="fill:none;stroke:#139c5a;stroke-miterlimit:10"/><polygon points="254.5 75.67 247.28 95.85 226.19 99.69 212.32 83.34 219.55 63.16 240.64 59.32 254.5 75.67" style="fill:#e21c84;stroke:#fff;stroke-miterlimit:10;opacity:0.2"/></svg>
00 /* colors */
11
2 :root {
3 --pst-color-primary: 19, 156, 90;
4 --pst-color-active-navigation: 19, 156, 90;
5 --pst-color-h2: var(--color-text-base);
2 html[data-theme="light"] {
3 --pst-color-primary: rgb(19, 156, 90);
4 --pst-color-secondary: rgb(231, 4, 136);
65 }
6
7 html[data-theme="dark"] {
8 --pst-color-primary: rgb(19, 156, 90);
9 --pst-color-secondary: rgb(231, 4, 136);
10 }
11
712
813 /* buttons */
914
1015 .button>p>a {
1116 box-shadow: 0px 4px 14px -7px #999999;
12 background-color: white;
17 /* background-color: white; */
1318 border: 1px solid #bbbbbb;
1419 display: inline-block;
1520 cursor: pointer;
2328 }
2429
2530 .button>p>a:hover {
26 border-color: #139C5A;
27 color: #e32e00;
31 border-color: rgb(19, 156, 90);
32 color: rgb(231, 4, 136);
2833 }
2934
3035 .button>p>a:active {
3136 position: relative;
3237 top: 1px;
33 }
38 }
4545
4646 You can download all version in SVG and PNG from [GitHub repository](https://github.com/geopandas/geopandas/tree/main/doc/source/_static/logo).
4747
48
4948 ## Colors
5049
5150 Pink and yellow accent colors are shared with `pandas`.
5251
5352 ### Green
53
5454 ```{raw} html
5555 <svg xmlns="http://www.w3.org/2000/svg" width="75" height="75" style="float: left">
5656 <circle cx="33" cy="33" r="33" fill="#139C5A"></circle>
5757 </svg>
5858 ```
59
5960 **HEX:** #139C5A
6061
6162 **RGB:** (19, 156, 90)
6263
6364 ### Yellow
65
6466 ```{raw} html
6567 <svg xmlns="http://www.w3.org/2000/svg" width="75" height="75" style="float: left">
6668 <circle cx="33" cy="33" r="33" fill="#FFCA00"></circle>
6769 </svg>
6870 ```
71
6972 **HEX:** #FFCA00
7073
7174 **RGB:** (255, 202, 0)
7275
7376 ### Pink
77
7478 ```{raw} html
7579 <svg xmlns="http://www.w3.org/2000/svg" width="75" height="75" style="float: left">
7680 <circle cx="33" cy="33" r="33" fill="#E70488"></circle>
7781 </svg>
7882 ```
83
7984 **HEX:** #E70488
8085
81 **RGB:** ((31, 4, 136)
82
83
86 **RGB:** (231, 4, 136)
00 # Roadmap
1
2 This page provides an overview of the strategic goals for development of GeoPandas. Some
3 of the tasks may happen sooner given the appropriate funding, other later with no
4 specified date, and some may not happen at all if the implementation proves to be
5 against the will of the community or face technical issues preventing their inclusion in
6 the code base.
7
8 The current roadmap is divided into two milestones. The first milestone aims at a
9 release of the first major version of GeoPandas, while the second milestone is a
10 longer-term vision covering enhancements that should happen in subsequent releases.
111
212 ## Roadmap for GeoPandas 1.0
313
4 WIP
14 ### Fully vectorized geometry engine
15
16 GeoPandas uses `shapely` as its geometry engine, based on scalar geometries, requiring a
17 loop-based implementation of most GeoPandas methods. That comes at a significant
18 performance cost, which is being resolved in shapely 2.0, a new major release resulting
19 from a complete rewrite of the internals using the vectorized implementation prototyped
20 in the `PyGEOS` project. At this moment, GeoPandas supports `shapely<2.0`,
21 `shapely>=2.0`, and `PyGEOS` as possible geometry engines, which causes friction in the
22 development process and uneven performance on the user side based on what geometry
23 engine the user happens to be using.
24
25 GeoPandas 1.0 will require `shapely>=2.0` and deprecate both older shapely and `PyGEOS`
26 engines. This change should simplify the code base allowing more manageable maintenance
27 and a lower barrier to entry for new contributors.
28
29 ### Feature parity with shapely
30
31 Even though GeoPandas uses shapely as the geometry engine, not all its functions are
32 exposed at a GeoPandas level. This has resulted in a less convenient API and a need to
33 switch between `GeoSeries` objects and lists or arrays of geometries, potentially
34 risking the data loss or corruption as the CRS is not included in such operations. In
35 the first phase, all element-wise operations (e.g. `segmentize`, or
36 `minimum_bounding_circle`) should be exposed as `GeoSeries` methods. The feature parity
37 should be reached in the second phase, covering all relevant functions.
38
39 ### Clarity of the API
40
41 The first version of the GeoPandas API is nearly ten years old. The PyData ecosystem has
42 significantly changed in the meantime, and some of the early decisions may no longer be
43 future-proof. Ahead of GeoPandas 1.0, the API will be revised to ensure that all the
44 necessary deprecations occur before the major release to provide the stability of the
45 API for the coming years.
46
47 ### Pruned dependencies
48
49 GeoPandas offers functionality for every step of a typical geospatial workflow, from
50 reading of the GIS file formats to geometry operations and handling of Coordinate
51 Reference Systems (CRS) and transformation of geometries between them. However, GIS I/O
52 depends on a relatively heavy C++ library `GDAL` and CRS management on another C++
53 library `PROJ`, even though not every application based on GeoPandas is necessarily
54 geospatial. GeoPandas 1.0 should eliminate the hard dependency on both `GDAL` and `PROJ`
55 and offer the basic capability of a GeoDataFrame with a minimal set of dependencies
56 limited to `pandas` and `shapely`.
57
58 ## Beyond GeoPandas 1.0
59
60 Additional work is planned for a longer time frame, stretching beyond GeoPandas 1.0
61 without a specific target release.
62
63 ### S2 geometry engine
64
65 The geometry engine used in GeoPandas is `shapely`, which serves as a Python API for
66 `GEOS`. It means that all geometry operations in GeoPandas are planar, using (possibly)
67 projected coordinate reference systems. Some applications focusing on the global context
68 may find planar operations limiting as they come with troubles around anti-meridian and
69 poles. One solution is an implementation of a spherical geometry engine, namely `S2`,
70 that should eliminate these limitations and offer an alternative to `GEOS`.
71
72 The GeoPandas community is currently working together with the R-spatial community that
73 has already exposed `S2` in an R counterpart of GeoPandas `sf` on Python bindings for
74 `S2`, that should be used as a secondary geometry engine in GeoPandas.
75
76 ### Lighter-weight geospatial I/O
77
78 In order to support lighter-weight installations of GeoPandas that do not depend on
79 heavier and difficult to install libraries such as GDAL, additional I/O libraries should
80 be developed and integrated into GeoPandas as optional dependencies. These should be
81 simpler to install and not require binary dependencies, which would lower the barrier to
82 entry for GeoPandas users that need basic I/O support for a limited number of GIS
83 formats such as ESRI Shapefiles or GeoPackages.
84
85 ### Prepared geometries
86
87 GeoPandas is using spatial indexing for the operations that may benefit from it. Further
88 performance gains can be achieved using prepared geometries. Preparation creates a
89 spatial index of individual line segments of geometries, greatly enhancing the speed of
90 spatial predicates like `intersects` or `contains`. Given that the preparation has
91 become less computationally expensive in `shapely` 2.0, GeoPandas should expose the
92 preparation to the user but, more importantly, use smart automatic geometry preparation
93 under the hood.
94
95 ### Static plotting improvements
96
97 GeoPandas currently covers a broad range of geospatial tasks, from data exploration to
98 advanced analysis. However, one moment may tempt the user to use different software -
99 plotting. GeoPandas can create static maps based on ``matplotlib``, but they are a bit
100 basic at the moment. It isn't straightforward to generate a complex map in a
101 production-quality which can go straight to an academic journal or an infographic. We
102 want to change this and remove barriers which we currently have and make it simple to
103 create beautiful maps.
44 GeoPandas is developed by more than [100 volunteer contributors](https://github.com/geopandas/geopandas/graphs/contributors).
55
66 ## Core developers
7
78 - Joris Van den Bossche - **lead maintainer** | [@jorisvandenbossche](https://github.com/jorisvandenbossche)
89 - Martin Fleischmann | [@martinfleis](https://github.com/martinfleis)
910 - James McBride | [@jdmcbr](https://github.com/jdmcbr)
1011 - Brendan Ward | [@brendan-ward](https://github.com/brendan-ward)
1112 - Levi Wolf | [@ljwolf](https://github.com/ljwolf)
13 - Matt Richards | [@m-richards](https://github.com/m-richards)
1214
1315 ## Founder
1416
55 :hidden:
66
77 Team <about/team>
8 Roadmap <about/roadmap>
89 Citing <about/citing>
910 Logo <about/logo>
1011 ```
11
1212
1313 GeoPandas is an open source project to add support for geographic data to pandas objects. It
1414 currently implements `GeoSeries` and `GeoDataFrame` types which are subclasses of
2424
2525 ```{container} button
2626
27 {doc}`Team <about/team>`
27 {doc}`Team <about/team>` {doc}`Roadmap <about/roadmap>`
2828 {doc}`Citing <about/citing>` {doc}`Logo <about/logo>`
2929 ```
3030
4848 - **2014**: GeoPandas 0.1.0 released
4949 - **2020**: GeoPandas became [NumFOCUS Affiliated
5050 Project](https://numfocus.org/sponsored-projects/affiliated-projects)
51
52
1313 import sys, os
1414 import warnings
1515
16 sys.path.insert(0, os.path.abspath("../.."))
17
18 import geopandas # noqa
19
1620 # If extensions (or modules to document with autodoc) are in another directory,
1721 # add these directories to sys.path here. If the directory is relative to the
1822 # documentation root, use os.path.abspath to make it absolute, like shown here.
3236 "sphinx.ext.autosummary",
3337 "sphinx.ext.intersphinx",
3438 "sphinx.ext.autodoc",
39 "sphinx.ext.linkcode",
3540 "myst_parser",
3641 "nbsphinx",
3742 "numpydoc",
8489 master_doc = "index"
8590
8691 # General information about the project.
87 project = u"GeoPandas"
88 copyright = u"2013–2022, GeoPandas developers"
92 project = "GeoPandas"
93 copyright = "2013–2022, GeoPandas developers"
8994
9095 # The version info for the project you're documenting, acts as replacement for
9196 # |version| and |release|, also used in various other places throughout the
259264 # Grouping the document tree into LaTeX files. List of tuples
260265 # (source start file, target name, title, author, documentclass [howto/manual]).
261266 latex_documents = [
262 ("index", "GeoPandas.tex", u"GeoPandas Documentation", u"Kelsey Jordahl", "manual")
267 ("index", "GeoPandas.tex", "GeoPandas Documentation", "Kelsey Jordahl", "manual")
263268 ]
264269
265270 # The name of an image file (relative to this directory) to place at the top of
287292
288293 # One entry per manual page. List of tuples
289294 # (source start file, name, description, authors, manual section).
290 man_pages = [("index", "geopandas", u"GeoPandas Documentation", [u"Kelsey Jordahl"], 1)]
295 man_pages = [("index", "geopandas", "GeoPandas Documentation", ["Kelsey Jordahl"], 1)]
291296
292297 # If true, show URL addresses after external links.
293298 # man_show_urls = False
302307 (
303308 "index",
304309 "GeoPandas",
305 u"GeoPandas Documentation",
306 u"Kelsey Jordahl",
310 "GeoPandas Documentation",
311 "Kelsey Jordahl",
307312 "GeoPandas",
308313 "One line description of project.",
309314 "Miscellaneous",
416421 "https://xyzservices.readthedocs.io/en/stable/",
417422 "https://xyzservices.readthedocs.io/en/stable/objects.inv",
418423 ),
424 "pyogrio": (
425 "https://pyogrio.readthedocs.io/en/stable/",
426 "https://pyogrio.readthedocs.io/en/stable/objects.inv",
427 ),
419428 }
429
430
431 # based on pandas implementation with added support of properties
432 def linkcode_resolve(domain, info):
433 """
434 Determine the URL corresponding to Python object
435 """
436 import inspect
437
438 if domain != "py":
439 return None
440
441 modname = info["module"]
442 fullname = info["fullname"]
443
444 submod = sys.modules.get(modname)
445 if submod is None:
446 return None
447
448 obj = submod
449 for part in fullname.split("."):
450 try:
451 with warnings.catch_warnings():
452 # Accessing deprecated objects will generate noisy warnings
453 warnings.simplefilter("ignore", FutureWarning)
454 obj = getattr(obj, part)
455 except AttributeError:
456 return None
457
458 try:
459 fn = inspect.getsourcefile(inspect.unwrap(obj))
460 except TypeError:
461 try: # property
462 fn = inspect.getsourcefile(inspect.unwrap(obj.fget))
463 except AttributeError:
464 fn = None
465 if not fn:
466 return None
467
468 try:
469 source, lineno = inspect.getsourcelines(obj)
470 except TypeError:
471 try: # property
472 source, lineno = inspect.getsourcelines(obj.fget)
473 except AttributeError:
474 lineno = None
475 except OSError:
476 lineno = None
477
478 if lineno:
479 linespec = f"#L{lineno}-L{lineno + len(source) - 1}"
480 else:
481 linespec = ""
482
483 fn = os.path.relpath(fn, start=os.path.dirname(geopandas.__file__))
484
485 if "+" in geopandas.__version__:
486 return (
487 f"https://github.com/geopandas/geopandas/blob/main/geopandas/{fn}{linespec}"
488 )
489 else:
490 return (
491 f"https://github.com/geopandas/geopandas/blob/"
492 f"v{geopandas.__version__}/geopandas/{fn}{linespec}"
493 )
8686 GeoSeries.convex_hull
8787 GeoSeries.envelope
8888 GeoSeries.simplify
89 GeoSeries.normalize
8990
9091 Affine transformations
9192 ----------------------
1717 .. attribute:: GeoSeries.boundary
1818
1919 Returns a :class:`~geopandas.GeoSeries` of lower dimensional objects representing
20 each geometries's set-theoretic `boundary`.
20 each geometry's set-theoretic `boundary`.
2121
2222 .. attribute:: GeoSeries.centroid
2323
176176 )
177177
178178
179 SQL WHERE Filter
180 ^^^^^^^^^^^^^^^^^
181
182 .. versionadded:: 0.12
183
184 Load in a subset of data with a `SQL WHERE clause <https://gdal.org/user/ogr_sql_dialect.html#where>`__.
185
186 .. note:: Requires Fiona 1.9+ or the pyogrio engine.
187
188 .. code-block:: python
189
190 gdf = geopandas.read_file(
191 geopandas.datasets.get_path("naturalearth_lowres"),
192 where="continent='Africa'",
193 )
194
195
179196 Writing Spatial Data
180197 ---------------------
181198
3939 "metadata": {},
4040 "outputs": [],
4141 "source": [
42 "df1 = pd.read_csv('volcano_data_2010.csv')\n",
42 "df1 = pd.read_csv(\"volcano_data_2010.csv\")\n",
4343 "\n",
4444 "# Keep only relevant columns\n",
4545 "df = df1.loc[:, (\"Year\", \"Name\", \"Country\", \"Latitude\", \"Longitude\", \"Type\")]\n",
5454 "source": [
5555 "# Create point geometries\n",
5656 "geometry = geopandas.points_from_xy(df.Longitude, df.Latitude)\n",
57 "geo_df = geopandas.GeoDataFrame(df[['Year','Name','Country', 'Latitude', 'Longitude', 'Type']], geometry=geometry)\n",
57 "geo_df = geopandas.GeoDataFrame(\n",
58 " df[[\"Year\", \"Name\", \"Country\", \"Latitude\", \"Longitude\", \"Type\"]], geometry=geometry\n",
59 ")\n",
5860 "\n",
5961 "geo_df.head()"
6062 ]
6567 "metadata": {},
6668 "outputs": [],
6769 "source": [
68 "world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))\n",
70 "world = geopandas.read_file(geopandas.datasets.get_path(\"naturalearth_lowres\"))\n",
6971 "df.Type.unique()"
7072 ]
7173 },
7981 },
8082 "outputs": [],
8183 "source": [
82 "fig, ax = plt.subplots(figsize=(24,18))\n",
83 "world.plot(ax=ax, alpha=0.4, color='grey')\n",
84 "geo_df.plot(column='Type', ax=ax, legend=True)\n",
85 "plt.title('Volcanoes')"
84 "fig, ax = plt.subplots(figsize=(24, 18))\n",
85 "world.plot(ax=ax, alpha=0.4, color=\"grey\")\n",
86 "geo_df.plot(column=\"Type\", ax=ax, legend=True)\n",
87 "plt.title(\"Volcanoes\")"
8688 ]
8789 },
8890 {
100102 "outputs": [],
101103 "source": [
102104 "# Stamen Terrain\n",
103 "map = folium.Map(location = [13.406,80.110], tiles = \"Stamen Terrain\", zoom_start = 9)\n",
105 "map = folium.Map(location=[13.406, 80.110], tiles=\"Stamen Terrain\", zoom_start=9)\n",
104106 "map"
105107 ]
106108 },
111113 "outputs": [],
112114 "source": [
113115 "# OpenStreetMap\n",
114 "map = folium.Map(location = [13.406,80.110], tiles='OpenStreetMap' , zoom_start = 9)\n",
116 "map = folium.Map(location=[13.406, 80.110], tiles=\"OpenStreetMap\", zoom_start=9)\n",
115117 "map"
116118 ]
117119 },
122124 "outputs": [],
123125 "source": [
124126 "# Stamen Toner\n",
125 "map = folium.Map(location = [13.406,80.110], tiles='Stamen Toner', zoom_start = 9)\n",
127 "map = folium.Map(location=[13.406, 80.110], tiles=\"Stamen Toner\", zoom_start=9)\n",
126128 "map"
127129 ]
128130 },
140142 "outputs": [],
141143 "source": [
142144 "# Use terrain map layer to see volcano terrain\n",
143 "map = folium.Map(location = [4,10], tiles = \"Stamen Terrain\", zoom_start = 3)"
145 "map = folium.Map(location=[4, 10], tiles=\"Stamen Terrain\", zoom_start=3)"
144146 ]
145147 },
146148 {
158160 "outputs": [],
159161 "source": [
160162 "# Create a geometry list from the GeoDataFrame\n",
161 "geo_df_list = [[point.xy[1][0], point.xy[0][0]] for point in geo_df.geometry ]\n",
163 "geo_df_list = [[point.xy[1][0], point.xy[0][0]] for point in geo_df.geometry]\n",
162164 "\n",
163165 "# Iterate through list and add a marker for each volcano, color-coded by its type.\n",
164166 "i = 0\n",
165167 "for coordinates in geo_df_list:\n",
166 " #assign a color marker for the type of volcano, Strato being the most common\n",
168 " # assign a color marker for the type of volcano, Strato being the most common\n",
167169 " if geo_df.Type[i] == \"Stratovolcano\":\n",
168170 " type_color = \"green\"\n",
169171 " elif geo_df.Type[i] == \"Complex volcano\":\n",
175177 " else:\n",
176178 " type_color = \"purple\"\n",
177179 "\n",
178 "\n",
179180 " # Place the markers with the popup labels and data\n",
180 " map.add_child(folium.Marker(location = coordinates,\n",
181 " popup =\n",
182 " \"Year: \" + str(geo_df.Year[i]) + '<br>' +\n",
183 " \"Name: \" + str(geo_df.Name[i]) + '<br>' +\n",
184 " \"Country: \" + str(geo_df.Country[i]) + '<br>'\n",
185 " \"Type: \" + str(geo_df.Type[i]) + '<br>'\n",
186 " \"Coordinates: \" + str(geo_df_list[i]),\n",
187 " icon = folium.Icon(color = \"%s\" % type_color)))\n",
181 " map.add_child(\n",
182 " folium.Marker(\n",
183 " location=coordinates,\n",
184 " popup=\n",
185 " \"Year: \" + str(geo_df.Year[i]) + \"<br>\"\n",
186 " + \"Name: \" + str(geo_df.Name[i]) + \"<br>\"\n",
187 " + \"Country: \" + str(geo_df.Country[i]) + \"<br>\"\n",
188 " + \"Type: \" + str(geo_df.Type[i]) + \"<br>\"\n",
189 " + \"Coordinates: \" + str(geo_df_list[i]),\n",
190 " icon=folium.Icon(color=\"%s\" % type_color),\n",
191 " )\n",
192 " )\n",
188193 " i = i + 1"
189194 ]
190195 },
217222 "\n",
218223 "from folium import plugins\n",
219224 "\n",
220 "map = folium.Map(location = [15,30], tiles='Cartodb dark_matter', zoom_start = 2)\n",
221 "\n",
222 "heat_data = [[point.xy[1][0], point.xy[0][0]] for point in geo_df.geometry ]\n",
225 "map = folium.Map(location=[15, 30], tiles=\"Cartodb dark_matter\", zoom_start=2)\n",
226 "\n",
227 "heat_data = [[point.xy[1][0], point.xy[0][0]] for point in geo_df.geometry]\n",
223228 "\n",
224229 "heat_data\n",
225230 "plugins.HeatMap(heat_data).add_to(map)\n",
201201 "cell_type": "markdown",
202202 "metadata": {},
203203 "source": [
204 "We're not limited to using the `intersection` binary predicate. Any of the `Shapely` geometry methods that return a Boolean can be used by specifying the `op` kwarg."
204 "We're not limited to using the `intersection` binary predicate. Any of the `Shapely` geometry methods that return a Boolean can be used by specifying the `predicate` kwarg."
205205 ]
206206 },
207207 {
160160 Using the optional PyGEOS dependency
161161 ------------------------------------
162162
163 .. attention::
164
165 The upcoming Shapely 2.0 release will absorb all improvements from PyGEOS.
166 If you are considering trying out those improvements, you can also test
167 the prerelease of Shapely instead.
168 See https://shapely.readthedocs.io/en/latest/release/2.x.html#version-2-0-0
169 for the release notes of Shapely 2.0, and https://github.com/shapely/shapely/discussions/1464
170 on how to install this and give feedback.
171
163172 Work is ongoing to improve the performance of GeoPandas. Currently, the
164173 fast implementations of basic spatial operations live in the `PyGEOS`_
165 package (but work is under way to contribute those improvements to Shapely).
174 package (but work is under way to contribute those improvements to Shapely,
175 coming to Shapely 2.0).
166176 Starting with GeoPandas 0.8, it is possible to optionally use those
167177 experimental speedups by installing PyGEOS. This can be done with conda
168178 (using the conda-forge channel) or pip::
181191 - You can still toggle the use of PyGEOS when it is available, by:
182192
183193 - Setting an environment variable (``USE_PYGEOS=0/1``). Note this variable
184 is only checked at first import of GeoPandas.
194 is only checked at first import of GeoPandas. You can set this environment
195 variable before starting the python process, or in your code right before
196 importing geopandas:
197
198 .. code-block:: python
199
200 import os
201 os.environ["USE_PYGEOS"] = "0"
202 import geopandas
203
185204 - Setting an option: ``geopandas.options.use_pygeos = True/False``. Note,
186205 although this variable can be set during an interactive session, it will
187206 only work if the GeoDataFrames you use are created (e.g. reading a file
188207 with ``read_file``) after changing this value.
208 Attention: changing this option will no longer work in all cases when
209 having Shapely >=2.0 installed. In that case, use the environment variable
210 (see option above).
189211
190212 .. warning::
191213
2828
2929 SHAPELY_GE_18 = Version(shapely.__version__) >= Version("1.8")
3030 SHAPELY_GE_182 = Version(shapely.__version__) >= Version("1.8.2")
31 SHAPELY_GE_20 = Version(shapely.__version__) >= Version("2.0")
31 SHAPELY_GE_20 = Version(shapely.__version__) >= Version("2.0.0.dev0")
32 SHAPELY_G_20a1 = Version(shapely.__version__) > Version("2.0a1")
3233
3334 GEOS_GE_390 = shapely.geos.geos_version >= (3, 9, 0)
3435
3536
3637 HAS_PYGEOS = None
3738 USE_PYGEOS = None
39 USE_SHAPELY_20 = None
3840 PYGEOS_SHAPELY_COMPAT = None
3941
4042 PYGEOS_GE_09 = None
7375 Alternatively, pass a value here to force a True/False value.
7476 """
7577 global USE_PYGEOS
78 global USE_SHAPELY_20
7679 global PYGEOS_SHAPELY_COMPAT
80
81 env_use_pygeos = os.getenv("USE_PYGEOS", None)
7782
7883 if val is not None:
7984 USE_PYGEOS = bool(val)
8287
8388 USE_PYGEOS = HAS_PYGEOS
8489
85 env_use_pygeos = os.getenv("USE_PYGEOS", None)
8690 if env_use_pygeos is not None:
8791 USE_PYGEOS = bool(int(env_use_pygeos))
8892
9397
9498 # validate the pygeos version
9599 if not Version(pygeos.__version__) >= Version("0.8"):
96 raise ImportError(
97 "PyGEOS >= 0.8 is required, version {0} is installed".format(
98 pygeos.__version__
100 if SHAPELY_GE_20:
101 USE_PYGEOS = False
102 warnings.warn(
103 "The PyGEOS version is too old, and Shapely >= 2 is installed, "
104 "thus using Shapely by default and not PyGEOS."
99105 )
100 )
106 else:
107 raise ImportError(
108 "PyGEOS >= 0.8 is required, version {0} is installed".format(
109 pygeos.__version__
110 )
111 )
101112
102113 # Check whether Shapely and PyGEOS use the same GEOS version.
103114 # Based on PyGEOS from_shapely implementation.
122133 except ImportError:
123134 raise ImportError(INSTALL_PYGEOS_ERROR)
124135
136 if USE_PYGEOS and env_use_pygeos is None and SHAPELY_GE_20:
137 warnings.warn(
138 "Shapely 2.0 is installed, but because PyGEOS is also installed, "
139 "GeoPandas will still use PyGEOS by default for now. To force to use and "
140 "test Shapely 2.0, you have to set the environment variable USE_PYGEOS=0. "
141 "You can do this before starting the Python process, or in your code "
142 "before importing geopandas:"
143 "\n\nimport os\nos.environ['USE_PYGEOS'] = '0'\nimport geopandas\n\n"
144 "In a future release, GeoPandas will switch to using Shapely by default. "
145 "If you are using PyGEOS directly (calling PyGEOS functions on geometries "
146 "from GeoPandas), this will then stop working and you are encouraged to "
147 "migrate from PyGEOS to Shapely 2.0 "
148 "(https://shapely.readthedocs.io/en/latest/migration_pygeos.html).",
149 stacklevel=6,
150 )
151
152 USE_SHAPELY_20 = (not USE_PYGEOS) and SHAPELY_GE_20
153
125154
126155 set_use_pygeos()
127156
88 import numpy as np
99 import pandas as pd
1010
11 import shapely
1112 import shapely.geometry
1213 import shapely.geos
1314 import shapely.ops
1415 import shapely.wkb
1516 import shapely.wkt
17 import shapely.validation
1618
1719 from shapely.geometry.base import BaseGeometry
1820
3739 "GEOMETRYCOLLECTION": "GeometryCollection",
3840 }
3941
40 if compat.USE_PYGEOS:
41 type_mapping = {p.value: _names[p.name] for p in pygeos.GeometryType}
42 if compat.USE_SHAPELY_20 or compat.USE_PYGEOS:
43 if compat.USE_SHAPELY_20:
44 type_mapping = {p.value: _names[p.name] for p in shapely.GeometryType}
45 else:
46 type_mapping = {p.value: _names[p.name] for p in pygeos.GeometryType}
4247 geometry_type_ids = list(type_mapping.keys())
4348 geometry_type_values = np.array(list(type_mapping.values()), dtype=object)
4449 else:
6772 return None
6873
6974 if compat.PYGEOS_SHAPELY_COMPAT:
70 geom = shapely.geos.lgeos.GEOSGeom_clone(geom._ptr)
71 return shapely.geometry.base.geom_factory(geom)
75 # we can only use this compatible fast path for shapely < 2, because
76 # shapely 2+ doesn't expose clone
77 if not compat.SHAPELY_GE_20:
78 geom = shapely.geos.lgeos.GEOSGeom_clone(geom._ptr)
79 return shapely.geometry.base.geom_factory(geom)
7280
7381 # fallback going through WKB
7482 if pygeos.is_empty(geom) and pygeos.get_type_id(geom) == 0:
160168 """
161169 Convert a list or array of WKB objects to a np.ndarray[geoms].
162170 """
171 if compat.USE_SHAPELY_20:
172 return shapely.from_wkb(data)
163173 if compat.USE_PYGEOS:
164174 return pygeos.from_wkb(data)
165
166 import shapely.wkb
167175
168176 out = []
169177
181189
182190
183191 def to_wkb(data, hex=False, **kwargs):
184 if compat.USE_PYGEOS:
192 if compat.USE_SHAPELY_20:
193 return shapely.to_wkb(data, hex=hex, **kwargs)
194 elif compat.USE_PYGEOS:
185195 return pygeos.to_wkb(data, hex=hex, **kwargs)
186196 else:
187197 if hex:
195205 """
196206 Convert a list or array of WKT objects to a np.ndarray[geoms].
197207 """
208 if compat.USE_SHAPELY_20:
209 return shapely.from_wkt(data)
198210 if compat.USE_PYGEOS:
199211 return pygeos.from_wkt(data)
200
201 import shapely.wkt
202212
203213 out = []
204214
218228
219229
220230 def to_wkt(data, **kwargs):
221 if compat.USE_PYGEOS:
231 if compat.USE_SHAPELY_20:
232 return shapely.to_wkt(data, **kwargs)
233 elif compat.USE_PYGEOS:
222234 return pygeos.to_wkt(data, **kwargs)
223235 else:
224236 out = [geom.wkt if geom is not None else None for geom in data]
245257 if z is not None:
246258 z = np.asarray(z, dtype="float64")
247259
248 if compat.USE_PYGEOS:
260 if compat.USE_SHAPELY_20:
261 return shapely.points(x, y, z)
262 elif compat.USE_PYGEOS:
249263 return pygeos.points(x, y, z)
250264 else:
251265 out = _points_from_xy(x, y, z)
463477
464478
465479 def is_valid(data):
466 if compat.USE_PYGEOS:
480 if compat.USE_SHAPELY_20:
481 return shapely.is_valid(data)
482 elif compat.USE_PYGEOS:
467483 return pygeos.is_valid(data)
468484 else:
469485 return _unary_op("is_valid", data, null_value=False)
470486
471487
472488 def is_empty(data):
473 if compat.USE_PYGEOS:
489 if compat.USE_SHAPELY_20:
490 return shapely.is_empty(data)
491 elif compat.USE_PYGEOS:
474492 return pygeos.is_empty(data)
475493 else:
476494 return _unary_op("is_empty", data, null_value=False)
477495
478496
479497 def is_simple(data):
480 if compat.USE_PYGEOS:
498 if compat.USE_SHAPELY_20:
499 return shapely.is_simple(data)
500 elif compat.USE_PYGEOS:
481501 return pygeos.is_simple(data)
482502 else:
483503 return _unary_op("is_simple", data, null_value=False)
499519 for geom in data:
500520 if geom is None:
501521 results.append(False)
502 elif geom.type == "Polygon":
522 elif geom.geom_type == "Polygon":
503523 results.append(geom.exterior.is_ring)
504 elif geom.type in ["LineString", "LinearRing"]:
524 elif geom.geom_type in ["LineString", "LinearRing"]:
505525 results.append(geom.is_ring)
506526 else:
507527 results.append(False)
509529
510530
511531 def is_closed(data):
512 if compat.USE_PYGEOS:
532 if compat.USE_SHAPELY_20:
533 return shapely.is_closed(data)
534 elif compat.USE_PYGEOS:
513535 return pygeos.is_closed(data)
514536 else:
515537 return _unary_op("is_closed", data, null_value=False)
516538
517539
518540 def has_z(data):
519 if compat.USE_PYGEOS:
541 if compat.USE_SHAPELY_20:
542 return shapely.has_z(data)
543 elif compat.USE_PYGEOS:
520544 return pygeos.has_z(data)
521545 else:
522546 return _unary_op("has_z", data, null_value=False)
523547
524548
525549 def geom_type(data):
526 if compat.USE_PYGEOS:
550 if compat.USE_SHAPELY_20:
551 res = shapely.get_type_id(data)
552 return geometry_type_values[np.searchsorted(geometry_type_ids, res)]
553 elif compat.USE_PYGEOS:
527554 res = pygeos.get_type_id(data)
528555 return geometry_type_values[np.searchsorted(geometry_type_ids, res)]
529556 else:
531558
532559
533560 def area(data):
534 if compat.USE_PYGEOS:
561 if compat.USE_SHAPELY_20:
562 return shapely.area(data)
563 elif compat.USE_PYGEOS:
535564 return pygeos.area(data)
536565 else:
537566 return _unary_op("area", data, null_value=np.nan)
538567
539568
540569 def length(data):
541 if compat.USE_PYGEOS:
570 if compat.USE_SHAPELY_20:
571 return shapely.length(data)
572 elif compat.USE_PYGEOS:
542573 return pygeos.length(data)
543574 else:
544575 return _unary_op("length", data, null_value=np.nan)
560591
561592
562593 def boundary(data):
563 if compat.USE_PYGEOS:
594 if compat.USE_SHAPELY_20:
595 return shapely.boundary(data)
596 elif compat.USE_PYGEOS:
564597 return pygeos.boundary(data)
565598 else:
566599 return _unary_geo("boundary", data)
567600
568601
569602 def centroid(data):
570 if compat.USE_PYGEOS:
603 if compat.USE_SHAPELY_20:
604 return shapely.centroid(data)
605 elif compat.USE_PYGEOS:
571606 return pygeos.centroid(data)
572607 else:
573608 return _unary_geo("centroid", data)
574609
575610
576611 def convex_hull(data):
577 if compat.USE_PYGEOS:
612 if compat.USE_SHAPELY_20:
613 return shapely.convex_hull(data)
614 elif compat.USE_PYGEOS:
578615 return pygeos.convex_hull(data)
579616 else:
580617 return _unary_geo("convex_hull", data)
581618
582619
583620 def envelope(data):
584 if compat.USE_PYGEOS:
621 if compat.USE_SHAPELY_20:
622 return shapely.envelope(data)
623 elif compat.USE_PYGEOS:
585624 return pygeos.envelope(data)
586625 else:
587626 return _unary_geo("envelope", data)
588627
589628
590629 def exterior(data):
591 if compat.USE_PYGEOS:
630 if compat.USE_SHAPELY_20:
631 return shapely.get_exterior_ring(data)
632 elif compat.USE_PYGEOS:
592633 return pygeos.get_exterior_ring(data)
593634 else:
594635 return _unary_geo("exterior", data)
638679
639680
640681 def covers(data, other):
641 if compat.USE_PYGEOS:
682 if compat.USE_SHAPELY_20:
683 return shapely.covers(data, other)
684 elif compat.USE_PYGEOS:
642685 return _binary_method("covers", data, other)
643686 else:
644687 return _binary_predicate("covers", data, other)
645688
646689
647690 def covered_by(data, other):
648 if compat.USE_PYGEOS:
691 if compat.USE_SHAPELY_20:
692 return shapely.covered_by(data, other)
693 elif compat.USE_PYGEOS:
649694 return _binary_method("covered_by", data, other)
650695 else:
651696 raise NotImplementedError(
654699
655700
656701 def contains(data, other):
657 if compat.USE_PYGEOS:
702 if compat.USE_SHAPELY_20:
703 return shapely.contains(data, other)
704 elif compat.USE_PYGEOS:
658705 return _binary_method("contains", data, other)
659706 else:
660707 return _binary_predicate("contains", data, other)
661708
662709
663710 def crosses(data, other):
664 if compat.USE_PYGEOS:
711 if compat.USE_SHAPELY_20:
712 return shapely.crosses(data, other)
713 elif compat.USE_PYGEOS:
665714 return _binary_method("crosses", data, other)
666715 else:
667716 return _binary_predicate("crosses", data, other)
668717
669718
670719 def disjoint(data, other):
671 if compat.USE_PYGEOS:
720 if compat.USE_SHAPELY_20:
721 return shapely.disjoint(data, other)
722 elif compat.USE_PYGEOS:
672723 return _binary_method("disjoint", data, other)
673724 else:
674725 return _binary_predicate("disjoint", data, other)
675726
676727
677728 def equals(data, other):
678 if compat.USE_PYGEOS:
729 if compat.USE_SHAPELY_20:
730 return shapely.equals(data, other)
731 elif compat.USE_PYGEOS:
679732 return _binary_method("equals", data, other)
680733 else:
681734 return _binary_predicate("equals", data, other)
682735
683736
684737 def intersects(data, other):
685 if compat.USE_PYGEOS:
738 if compat.USE_SHAPELY_20:
739 return shapely.intersects(data, other)
740 elif compat.USE_PYGEOS:
686741 return _binary_method("intersects", data, other)
687742 else:
688743 return _binary_predicate("intersects", data, other)
689744
690745
691746 def overlaps(data, other):
692 if compat.USE_PYGEOS:
747 if compat.USE_SHAPELY_20:
748 return shapely.overlaps(data, other)
749 elif compat.USE_PYGEOS:
693750 return _binary_method("overlaps", data, other)
694751 else:
695752 return _binary_predicate("overlaps", data, other)
696753
697754
698755 def touches(data, other):
699 if compat.USE_PYGEOS:
756 if compat.USE_SHAPELY_20:
757 return shapely.touches(data, other)
758 elif compat.USE_PYGEOS:
700759 return _binary_method("touches", data, other)
701760 else:
702761 return _binary_predicate("touches", data, other)
703762
704763
705764 def within(data, other):
706 if compat.USE_PYGEOS:
765 if compat.USE_SHAPELY_20:
766 return shapely.within(data, other)
767 elif compat.USE_PYGEOS:
707768 return _binary_method("within", data, other)
708769 else:
709770 return _binary_predicate("within", data, other)
710771
711772
712773 def equals_exact(data, other, tolerance):
713 if compat.USE_PYGEOS:
774 if compat.USE_SHAPELY_20:
775 return shapely.equals_exact(data, other, tolerance=tolerance)
776 elif compat.USE_PYGEOS:
714777 return _binary_method("equals_exact", data, other, tolerance=tolerance)
715778 else:
716779 return _binary_predicate("equals_exact", data, other, tolerance=tolerance)
717780
718781
719782 def almost_equals(self, other, decimal):
720 if compat.USE_PYGEOS:
783 if compat.USE_PYGEOS or compat.USE_SHAPELY_20:
721784 return self.equals_exact(other, 0.5 * 10 ** (-decimal))
722785 else:
723786 return _binary_predicate("almost_equals", self, other, decimal=decimal)
733796 return pygeos.clip_by_rect(data, xmin, ymin, xmax, ymax)
734797 else:
735798 clipped_geometries = np.empty(len(data), dtype=object)
736 clipped_geometries[:] = [
737 shapely.ops.clip_by_rect(s, xmin, ymin, xmax, ymax)
738 if s is not None
739 else None
740 for s in data
741 ]
799 with compat.ignore_shapely2_warnings():
800 clipped_geometries[:] = [
801 shapely.ops.clip_by_rect(s, xmin, ymin, xmax, ymax)
802 if s is not None
803 else None
804 for s in data
805 ]
742806 return clipped_geometries
743807
744808
745809 def difference(data, other):
746 if compat.USE_PYGEOS:
810 if compat.USE_SHAPELY_20:
811 return shapely.difference(data, other)
812 elif compat.USE_PYGEOS:
747813 return _binary_method("difference", data, other)
748814 else:
749815 return _binary_geo("difference", data, other)
750816
751817
752818 def intersection(data, other):
753 if compat.USE_PYGEOS:
819 if compat.USE_SHAPELY_20:
820 return shapely.intersection(data, other)
821 elif compat.USE_PYGEOS:
754822 return _binary_method("intersection", data, other)
755823 else:
756824 return _binary_geo("intersection", data, other)
757825
758826
759827 def symmetric_difference(data, other):
760 if compat.USE_PYGEOS:
828 if compat.USE_SHAPELY_20:
829 return shapely.symmetric_difference(data, other)
830 elif compat.USE_PYGEOS:
761831 return _binary_method("symmetric_difference", data, other)
762832 else:
763833 return _binary_geo("symmetric_difference", data, other)
764834
765835
766836 def union(data, other):
767 if compat.USE_PYGEOS:
837 if compat.USE_SHAPELY_20:
838 return shapely.union(data, other)
839 elif compat.USE_PYGEOS:
768840 return _binary_method("union", data, other)
769841 else:
770842 return _binary_geo("union", data, other)
776848
777849
778850 def distance(data, other):
779 if compat.USE_PYGEOS:
851 if compat.USE_SHAPELY_20:
852 return shapely.distance(data, other)
853 elif compat.USE_PYGEOS:
780854 return _binary_method("distance", data, other)
781855 else:
782856 return _binary_op_float("distance", data, other)
783857
784858
785859 def buffer(data, distance, resolution=16, **kwargs):
786 if compat.USE_PYGEOS:
860 if compat.USE_SHAPELY_20:
861 if compat.SHAPELY_G_20a1:
862 return shapely.buffer(data, distance, quad_segs=resolution, **kwargs)
863 else:
864 # TODO: temporary keep this (so geopandas works with latest released
865 # shapely, currently alpha1) until shapely beta1 is out
866 return shapely.buffer(data, distance, quadsegs=resolution, **kwargs)
867 elif compat.USE_PYGEOS:
787868 return pygeos.buffer(data, distance, quadsegs=resolution, **kwargs)
788869 else:
789870 out = np.empty(len(data), dtype=object)
814895
815896
816897 def interpolate(data, distance, normalized=False):
817 if compat.USE_PYGEOS:
898 if compat.USE_SHAPELY_20:
899 return shapely.line_interpolate_point(data, distance, normalized=normalized)
900 elif compat.USE_PYGEOS:
818901 try:
819902 return pygeos.line_interpolate_point(data, distance, normalized=normalized)
820903 except TypeError: # support for pygeos<0.9
842925
843926
844927 def simplify(data, tolerance, preserve_topology=True):
845 if compat.USE_PYGEOS:
928 if compat.USE_SHAPELY_20:
929 return shapely.simplify(data, tolerance, preserve_topology=preserve_topology)
930 elif compat.USE_PYGEOS:
846931 # preserve_topology has different default as pygeos!
847932 return pygeos.simplify(data, tolerance, preserve_topology=preserve_topology)
848933 else:
873958
874959
875960 def normalize(data):
876 if compat.USE_PYGEOS:
961 if compat.USE_SHAPELY_20:
962 return shapely.normalize(data)
963 elif compat.USE_PYGEOS:
877964 return pygeos.normalize(data)
965 elif compat.SHAPELY_GE_18:
966 out = np.empty(len(data), dtype=object)
967 with compat.ignore_shapely2_warnings():
968 out[:] = [geom.normalize() if geom is not None else None for geom in data]
878969 else:
879970 out = np.empty(len(data), dtype=object)
880971 with compat.ignore_shapely2_warnings():
881972 out[:] = [
882973 _shapely_normalize(geom) if geom is not None else None for geom in data
883974 ]
884 return out
975 return out
976
977
978 def make_valid(data):
979 if compat.USE_SHAPELY_20:
980 return shapely.make_valid(data)
981 elif compat.USE_PYGEOS:
982 return pygeos.make_valid(data)
983 elif not compat.SHAPELY_GE_18:
984 raise NotImplementedError(
985 f"shapely >= 1.8 or PyGEOS is required, "
986 f"version {shapely.__version__} is installed"
987 )
988 else:
989 out = np.empty(len(data), dtype=object)
990 with compat.ignore_shapely2_warnings():
991 out[:] = [
992 shapely.validation.make_valid(geom) if geom is not None else None
993 for geom in data
994 ]
995 return out
885996
886997
887998 def project(data, other, normalized=False):
888 if compat.USE_PYGEOS:
999 if compat.USE_SHAPELY_20:
1000 return shapely.line_locate_point(data, other, normalized=normalized)
1001 elif compat.USE_PYGEOS:
8891002 try:
8901003 return pygeos.line_locate_point(data, other, normalized=normalized)
8911004 except TypeError: # support for pygeos<0.9
8951008
8961009
8971010 def relate(data, other):
1011 if compat.USE_SHAPELY_20:
1012 return shapely.relate(data, other)
8981013 data = to_shapely(data)
8991014 if isinstance(other, np.ndarray):
9001015 other = to_shapely(other)
9021017
9031018
9041019 def unary_union(data):
905 if compat.USE_PYGEOS:
1020 if compat.USE_SHAPELY_20:
1021 data = shapely.union_all(data)
1022 if data is None: # shapely 2.0a1
1023 return None
1024 if data.is_empty: # shapely 2.0
1025 return None
1026 else:
1027 return data
1028 elif compat.USE_PYGEOS:
9061029 return _pygeos_to_shapely(pygeos.union_all(data))
9071030 else:
9081031 data = [g for g in data if g is not None]
9181041
9191042
9201043 def get_x(data):
921 if compat.USE_PYGEOS:
1044 if compat.USE_SHAPELY_20:
1045 return shapely.get_x(data)
1046 elif compat.USE_PYGEOS:
9221047 return pygeos.get_x(data)
9231048 else:
9241049 return _unary_op("x", data, null_value=np.nan)
9251050
9261051
9271052 def get_y(data):
928 if compat.USE_PYGEOS:
1053 if compat.USE_SHAPELY_20:
1054 return shapely.get_y(data)
1055 elif compat.USE_PYGEOS:
9291056 return pygeos.get_y(data)
9301057 else:
9311058 return _unary_op("y", data, null_value=np.nan)
9321059
9331060
9341061 def get_z(data):
935 if compat.USE_PYGEOS:
1062 if compat.USE_SHAPELY_20:
1063 return shapely.get_z(data)
1064 elif compat.USE_PYGEOS:
9361065 return pygeos.get_z(data)
9371066 else:
9381067 data = [geom.z if geom.has_z else np.nan for geom in data]
9401069
9411070
9421071 def bounds(data):
943 if compat.USE_PYGEOS:
1072 if compat.USE_SHAPELY_20:
1073 return shapely.bounds(data)
1074 elif compat.USE_PYGEOS:
9441075 return pygeos.bounds(data)
9451076 # ensure that for empty arrays, the result has the correct shape
9461077 if len(data) == 0:
9641095
9651096
9661097 def transform(data, func):
1098 if compat.USE_SHAPELY_20:
1099 coords = shapely.get_coordinates(data)
1100 new_coords = func(coords[:, 0], coords[:, 1])
1101 result = shapely.set_coordinates(data.copy(), np.array(new_coords).T)
1102 return result
9671103 if compat.USE_PYGEOS:
9681104 coords = pygeos.get_coordinates(data)
9691105 new_coords = func(coords[:, 0], coords[:, 1])
2222 # setup.py/versioneer.py will grep for the variable names, so they must
2323 # each be defined on a line of their own. _version.py will just call
2424 # get_keywords().
25 git_refnames = " (HEAD -> main, tag: v0.11.1)"
26 git_full = "1f7160050b31e0f39410c7f4163a2cbb2648ff62"
27 git_date = "2022-07-24 13:17:38 +0200"
25 git_refnames = " (HEAD -> main, tag: v0.12.0)"
26 git_full = "31f8e6af3b6ec57dc50633e2e1cdfb3a6e932a95"
27 git_date = "2022-10-24 09:06:05 +0200"
2828 keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
2929 return keywords
3030
107107 """
108108 Convert internal representation (PyGEOS or Shapely) to external Shapely object.
109109 """
110 if not compat.USE_PYGEOS:
110 if compat.USE_SHAPELY_20:
111 return geom
112 elif not compat.USE_PYGEOS:
111113 return geom
112114 else:
113115 return vectorized._pygeos_to_shapely(geom)
117119 """
118120 Convert external Shapely object to internal representation (PyGEOS or Shapely).
119121 """
120 if not compat.USE_PYGEOS:
122 if compat.USE_SHAPELY_20:
123 return geom
124 elif not compat.USE_PYGEOS:
121125 return geom
122126 else:
123127 return vectorized._shapely_to_pygeos(geom)
409413 # )
410414
411415 def __getstate__(self):
412 if compat.USE_PYGEOS:
416 if compat.USE_SHAPELY_20:
417 return (shapely.to_wkb(self.data), self._crs)
418 elif compat.USE_PYGEOS:
413419 return (pygeos.to_wkb(self.data), self._crs)
414420 else:
415421 return self.__dict__
503509
504510 def representative_point(self):
505511 return GeometryArray(vectorized.representative_point(self.data), crs=self.crs)
512
513 def normalize(self):
514 return GeometryArray(vectorized.normalize(self.data), crs=self.crs)
515
516 def make_valid(self):
517 return GeometryArray(vectorized.make_valid(self.data), crs=self.crs)
506518
507519 #
508520 # Binary predicates
10641076 """
10651077 Boolean NumPy array indicating if each value is missing
10661078 """
1067 if compat.USE_PYGEOS:
1079 if compat.USE_SHAPELY_20:
1080 return shapely.is_missing(self.data)
1081 elif compat.USE_PYGEOS:
10681082 return pygeos.is_missing(self.data)
10691083 else:
10701084 return np.array([g is None for g in self.data], dtype="bool")
13051319 ExtensionArray
13061320 """
13071321 data = np.concatenate([ga.data for ga in to_concat])
1308 return GeometryArray(data, crs=to_concat[0].crs)
1322 return GeometryArray(data, crs=_get_common_crs(to_concat))
13091323
13101324 def _reduce(self, name, skipna=True, **kwargs):
13111325 # including the base class version here (that raises by default)
13761390 else:
13771391 return False
13781392 return (self == item).any()
1393
1394
1395 def _get_common_crs(arr_seq):
1396
1397 crs_set = {arr.crs for arr in arr_seq}
1398 crs_not_none = [crs for crs in crs_set if crs is not None]
1399 names = [crs.name for crs in crs_not_none]
1400
1401 if len(crs_not_none) == 0:
1402 return None
1403 if len(crs_not_none) == 1:
1404 if len(crs_set) != 1:
1405 warnings.warn(
1406 "CRS not set for some of the concatenation inputs. "
1407 f"Setting output's CRS as {names[0]} "
1408 "(the single non-null crs provided)."
1409 )
1410 return crs_not_none[0]
1411
1412 raise ValueError(
1413 f"Cannot determine common CRS for concatenation inputs, got {names}. "
1414 "Use `to_crs()` to transform geometries to the same CRS before merging."
1415 )
423423 @property
424424 def boundary(self):
425425 """Returns a ``GeoSeries`` of lower dimensional objects representing
426 each geometries's set-theoretic `boundary`.
426 each geometry's set-theoretic `boundary`.
427427
428428 Examples
429429 --------
690690 GeoSeries.centroid : geometric centroid
691691 """
692692 return _delegate_geo_method("representative_point", self)
693
694 def normalize(self):
695 """Returns a ``GeoSeries`` of normalized geometries to normal form (or canonical form).
696
697 This method orders the coordinates, rings of a polygon and parts of
698 multi geometries consistently. Typically useful for testing purposes
699 (for example in combination with `equals_exact`).
700
701 Examples
702 --------
703
704 >>> from shapely.geometry import Polygon, LineString, Point
705 >>> s = geopandas.GeoSeries(
706 ... [
707 ... Polygon([(0, 0), (1, 1), (0, 1)]),
708 ... LineString([(0, 0), (1, 1), (1, 0)]),
709 ... Point(0, 0),
710 ... ],
711 ... crs='EPSG:3857'
712 ... )
713 >>> s
714 0 POLYGON ((0.000 0.000, 1.000 1.000, 0.000 1.00...
715 1 LINESTRING (0.000 0.000, 1.000 1.000, 1.000 0....
716 2 POINT (0.000 0.000)
717 dtype: geometry
718
719 >>> s.normalize()
720 0 POLYGON ((0.000 0.000, 0.000 1.000, 1.000 1.00...
721 1 LINESTRING (0.000 0.000, 1.000 1.000, 1.000 0....
722 2 POINT (0.000 0.000)
723 dtype: geometry
724 """
725 return _delegate_geo_method("normalize", self)
726
727 def make_valid(self):
728 """
729 Repairs invalid geometries.
730
731 Returns a ``GeoSeries`` with valid geometries.
732 If the input geometry is already valid, then it will be preserved.
733 In many cases, in order to create a valid geometry, the input
734 geometry must be split into multiple parts or multiple geometries.
735 If the geometry must be split into multiple parts of the same type
736 to be made valid, then a multi-part geometry will be returned
737 (e.g. a MultiPolygon).
738 If the geometry must be split into multiple parts of different types
739 to be made valid, then a GeometryCollection will be returned.
740
741 Examples
742 --------
743 >>> from shapely.geometry import MultiPolygon, Polygon, LineString, Point
744 >>> s = geopandas.GeoSeries(
745 ... [
746 ... Polygon([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)]),
747 ... Polygon([(0, 2), (0, 1), (2, 0), (0, 0), (0, 2)]),
748 ... LineString([(0, 0), (1, 1), (1, 0)]),
749 ... ],
750 ... crs='EPSG:3857',
751 ... )
752 >>> s
753 0 POLYGON ((0.000 0.000, 0.000 2.000, 1.000 1.00...
754 1 POLYGON ((0.000 2.000, 0.000 1.000, 2.000 0.00...
755 2 LINESTRING (0.000 0.000, 1.000 1.000, 1.000 0....
756 dtype: geometry
757
758 >>> s.make_valid()
759 0 MULTIPOLYGON (((1.000 1.000, 0.000 0.000, 0.00...
760 1 GEOMETRYCOLLECTION (POLYGON ((2.000 0.000, 0.0...
761 2 LINESTRING (0.000 0.000, 1.000 1.000, 1.000 0....
762 dtype: geometry
763 """
764 return _delegate_geo_method("make_valid", self)
693765
694766 #
695767 # Reduction operations that return a Shapely geometry
26262698 0 2.0 1.0 2.0 1.0
26272699 1 0.0 0.0 1.0 1.0
26282700 2 0.0 1.0 1.0 2.0
2701
2702 You can assign the bounds to the ``GeoDataFrame`` as:
2703
2704 >>> import pandas as pd
2705 >>> gdf = pd.concat([gdf, gdf.bounds], axis=1)
2706 >>> gdf
2707 geometry minx miny maxx maxy
2708 0 POINT (2.00000 1.00000) 2.0 1.0 2.0 1.0
2709 1 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 1.... 0.0 0.0 1.0 1.0
2710 2 LINESTRING (0.00000 1.00000, 1.00000 2.00000) 0.0 1.0 1.0 2.0
26292711 """
26302712 bounds = GeometryArray(self.geometry.values).bounds
26312713 return DataFrame(
00 # Datasets included with geopandas
11
22 - `'nybb'`: Borough boundaries of New York City, data provided Department of City Planning (DCP), https://data.cityofnewyork.us/City-Government/Borough-Boundaries/tqmj-j8zm
3 - `'naturalearth_cities'`: capital cities, based on http://www.naturalearthdata.com/downloads/10m-cultural-vectors/10m-populated-places/
3 - `'naturalearth_cities'`: capital cities, based on http://www.naturalearthdata.com/downloads/10m-cultural-vectors/110m-populated-places/
44 - `'naturalearth_lowres'`: country boundaries, based on http://www.naturalearthdata.com/downloads/110m-cultural-vectors/110m-admin-0-countries/
55
66
0 GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
0 GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]
00 """
1 Script that generates the included dataset 'naturalearth_lowres.shp'.
1 Script that generates the included dataset 'naturalearth_lowres.shp'
2 and 'naturalearth_cities.shp'.
23
34 Raw data: https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip
4 Current version used: version 5.0.1
5 Current version used: see code
56 """ # noqa (E501 link is longer than max line length)
67
78 import geopandas as gpd
9 import requests
10 from pathlib import Path
11 from zipfile import ZipFile
12 import tempfile
813
9 # assumes zipfile from naturalearthdata was downloaded to current directory
10 world_raw = gpd.read_file("zip://./ne_110m_admin_0_countries.zip")
14 version = "latest"
15 urlbase = "https://www.naturalearthdata.com/"
16 urlbase += "http//www.naturalearthdata.com/download/110m/cultural/"
1117
12 # not ideal - fix some country codes
13 mask = world_raw["ISO_A3"].eq("-99") & world_raw["TYPE"].isin(
14 ["Sovereign country", "Country"]
15 )
16 world_raw.loc[mask, "ISO_A3"] = world_raw.loc[mask, "ADM0_A3"]
1718
18 # subsets columns of interest for geopandas examples
19 world_df = world_raw[
20 ["POP_EST", "CONTINENT", "NAME", "ISO_A3", "GDP_MD", "geometry"]
21 ].rename(
22 columns={"GDP_MD": "GDP_MD_EST"}
23 ) # column has changed name...
24 world_df.columns = world_df.columns.str.lower()
19 def countries_override(world_raw):
20 # not ideal - fix some country codes
21 mask = world_raw["ISO_A3"].eq("-99") & world_raw["TYPE"].isin(
22 ["Sovereign country", "Country"]
23 )
24 world_raw.loc[mask, "ISO_A3"] = world_raw.loc[mask, "ADM0_A3"]
25 # backwards compatibility
26 return world_raw.rename(columns={"GDP_MD": "GDP_MD_EST"})
2527
26 world_df.to_file(
27 driver="ESRI Shapefile", filename="./naturalearth_lowres/naturalearth_lowres.shp"
28 )
28
29 # any change between versions?
30 def df_same(new, old, dataset, log):
31 assert (new.columns == old.columns).all(), "columns should be the same"
32 if new.shape != old.shape:
33 dfc = old.merge(new, on="name", how="outer", suffixes=("_old", "_new")).loc[
34 lambda d: d.isna().any(axis=1)
35 ]
36 log.append(f"### {dataset} row count changed ###\n{dfc.to_markdown()}")
37 return False
38 dfc = new.compare(old)
39 if len(dfc) > 0:
40 log.append(f"### {dataset} data changed ###\n{dfc.to_markdown()}")
41 return len(dfc) == 0
42
43
44 config = [
45 {
46 "file": "ne_110m_populated_places.zip",
47 "cols": ["NAME", "geometry"],
48 "current": gpd.datasets.get_path("naturalearth_cities"),
49 },
50 {
51 "file": "ne_110m_admin_0_countries.zip",
52 "cols": ["POP_EST", "CONTINENT", "NAME", "ISO_A3", "GDP_MD_EST", "geometry"],
53 "override": countries_override,
54 "current": gpd.datasets.get_path("naturalearth_lowres"),
55 },
56 ]
57
58 downloads = {}
59 log = []
60 for dl in config:
61 with tempfile.TemporaryDirectory() as tmpdirname:
62 url = urlbase + dl["file"]
63 r = requests.get(
64 url,
65 stream=True,
66 headers={"User-Agent": "XY"},
67 params=None if version == "latest" else {"version": version},
68 )
69 assert (
70 r.status_code == 200
71 ), f"version: {version} does not exist. status: {r.status_code}"
72
73 f = Path(tmpdirname).joinpath(dl["file"])
74 with open(f, "wb") as fd:
75 for chunk in r.iter_content(chunk_size=128):
76 fd.write(chunk)
77 # extract the natural earth version
78 z = ZipFile(f)
79 version_f = [i for i in z.infolist() if "VERSION" in i.filename]
80 assert len(version_f) == 1, "failed to find VERSION file"
81 with open(z.extract(version_f[0], Path(tmpdirname).joinpath("v.txt"))) as f_:
82 dl_version = f_.read().strip()
83
84 # extract geodataframe from zip
85 gdf = gpd.read_file(f)
86 # maintain structure that geopandas distributes
87 if "override" in dl.keys():
88 gdf = dl["override"](gdf)
89 gdf = gdf.loc[:, dl["cols"]]
90 gdf = gdf.rename(columns={c: c.lower() for c in gdf.columns})
91 # get changes between current version and new version
92 if not df_same(gdf, gpd.read_file(dl["current"]), dl["file"], log):
93 downloads[dl["file"]] = gdf
94
95
96 # create change log that can be pasted into PR
97 with open(f"CHANGE_{dl_version}.md", "w") as f:
98 f.write("\n\n".join(log))
99
100 # save downloaded geodataframe to appropriate place
101 for k, gdf_ in downloads.items():
102 f = [Path(c["current"]) for c in config if c["file"] == k][0]
103 gdf_.to_file(driver="ESRI Shapefile", filename=Path(f.parent.name).joinpath(f.name))
33 from shapely.geometry import LineString
44 import numpy as np
55 import pandas as pd
6
7 from packaging.version import Version
68
79 _MAP_KWARGS = [
810 "location",
261263
262264 >>> df.explore("pop_est", cmap="Blues") # doctest: +SKIP
263265 """
266
267 def _colormap_helper(_cmap, n_resample=None, idx=None):
268 """Helper for MPL deprecation - GH#2596"""
269 if not n_resample:
270 return cm.get_cmap(_cmap)
271 else:
272 if MPL_361:
273 return cm.get_cmap(_cmap).resampled(n_resample)(idx)
274 else:
275 return cm.get_cmap(_cmap, n_resample)(idx)
276
264277 try:
265278 import branca as bc
266279 import folium
267 import matplotlib.cm as cm
280 import matplotlib
268281 import matplotlib.colors as colors
269282 import matplotlib.pyplot as plt
270283 from mapclassify import classify
284
285 # isolate MPL version - GH#2596
286 MPL_361 = Version(matplotlib.__version__) >= Version("3.6.1")
287 if MPL_361:
288 from matplotlib import colormaps as cm
289 else:
290 import matplotlib.cm as cm
291
271292 except (ImportError, ModuleNotFoundError):
272293 raise ImportError(
273294 "The 'folium', 'matplotlib' and 'mapclassify' packages are required for "
377398 )
378399 categorical = True
379400 elif (
380 gdf[column].dtype is np.dtype("O")
381 or gdf[column].dtype is np.dtype(bool)
401 pd.api.types.is_object_dtype(gdf[column])
402 or pd.api.types.is_bool_dtype(gdf[column])
403 or pd.api.types.is_string_dtype(gdf[column])
382404 or categories
383405 ):
384406 categorical = True
394416 if cmap in plt.colormaps():
395417
396418 color = np.apply_along_axis(
397 colors.to_hex, 1, cm.get_cmap(cmap, N)(cat.codes)
419 colors.to_hex,
420 1,
421 _colormap_helper(cmap, n_resample=N, idx=cat.codes),
398422 )
399423 legend_colors = np.apply_along_axis(
400 colors.to_hex, 1, cm.get_cmap(cmap, N)(range(N))
424 colors.to_hex, 1, _colormap_helper(cmap, n_resample=N, idx=range(N))
401425 )
402426
403427 # colormap is matplotlib.Colormap
438462 np.asarray(gdf[column][~nan_idx]), scheme, **classification_kwds
439463 )
440464 color = np.apply_along_axis(
441 colors.to_hex, 1, cm.get_cmap(cmap, k)(binning.yb)
465 colors.to_hex,
466 1,
467 _colormap_helper(cmap, n_resample=k, idx=binning.yb),
442468 )
443469
444470 else:
449475 )
450476
451477 color = np.apply_along_axis(
452 colors.to_hex, 1, cm.get_cmap(cmap, 256)(binning.yb)
478 colors.to_hex,
479 1,
480 _colormap_helper(cmap, n_resample=256, idx=binning.yb),
453481 )
454482
455483 # set default style
620648 colormap_kwds["max_labels"] = legend_kwds.pop("max_labels")
621649 if scheme:
622650 cb_colors = np.apply_along_axis(
623 colors.to_hex, 1, cm.get_cmap(cmap, binning.k)(range(binning.k))
651 colors.to_hex,
652 1,
653 _colormap_helper(cmap, n_resample=binning.k, idx=range(binning.k)),
624654 )
625655 if cbar:
626656 if legend_kwds.pop("scale", True):
654684 if isinstance(cmap, bc.colormap.ColorMap):
655685 colorbar = cmap
656686 else:
657
658 mp_cmap = cm.get_cmap(cmap)
687 mp_cmap = _colormap_helper(cmap)
659688 cb_colors = np.apply_along_axis(
660689 colors.to_hex, 1, mp_cmap(range(mp_cmap.N))
661690 )
691
662692 # linear legend
663693 if mp_cmap.N > 20:
664694 colorbar = bc.colormap.LinearColormap(
122122 GeoSeries : Series object designed to store shapely geometry objects
123123 """
124124
125 # TODO: remove "_crs" in 0.12
126 _metadata = ["_crs", "_geometry_column_name"]
125 _metadata = ["_geometry_column_name"]
126
127 _internal_names = DataFrame._internal_names + ["geometry"]
128 _internal_names_set = set(_internal_names)
127129
128130 _geometry_column_name = DEFAULT_GEO_COLUMN_NAME
129131
130132 def __init__(self, data=None, *args, geometry=None, crs=None, **kwargs):
131133 with compat.ignore_shapely2_warnings():
132134 super().__init__(data, *args, **kwargs)
133
134 # TODO: to be removed in 0.12
135 self._crs = None
136135
137136 # set_geometry ensures the geometry data have the proper dtype,
138137 # but is not called if `geometry=None` ('geometry' column present
346345 level = _ensure_geometry(level, crs=crs)
347346 frame[geo_column_name] = level
348347 frame._geometry_column_name = geo_column_name
349
350 # TODO: to be removed in 0.12
351 frame._crs = level.crs
352348 if not inplace:
353349 return frame
354350
430426 GeoDataFrame.to_crs : re-project to another CRS
431427
432428 """
433 # TODO: remove try/except in 0.12
434429 try:
435430 return self.geometry.crs
436431 except AttributeError:
437 # the active geometry column might not be set
438 warnings.warn(
439 "Accessing CRS of a GeoDataFrame without a geometry column is "
440 "deprecated and will be removed in GeoPandas 0.12. "
441 "Use GeoDataFrame.set_geometry to set the active geometry column.",
442 FutureWarning,
443 stacklevel=2,
432 raise AttributeError(
433 "The CRS attribute of a GeoDataFrame without an active "
434 "geometry column is not defined. Use GeoDataFrame.set_geometry "
435 "to set the active geometry column."
444436 )
445 return self._crs
446437
447438 @crs.setter
448439 def crs(self, value):
458449 self.geometry.values.crs = value
459450 else:
460451 # column called 'geometry' without geometry
461 self._crs = None if not value else CRS.from_user_input(value)
462
463 # TODO: raise this error in 0.12. This already raises a FutureWarning
464 # TODO: defined in the crs property above
465 # raise ValueError(
466 # "Assigning CRS to a GeoDataFrame without an active geometry "
467 # "column is not supported. Use GeoDataFrame.set_geometry to set "
468 # "the active geometry column.",
469 # )
452 raise ValueError(
453 "Assigning CRS to a GeoDataFrame without an active geometry "
454 "column is not supported. Use GeoDataFrame.set_geometry to set "
455 "the active geometry column.",
456 )
470457
471458 def __setstate__(self, state):
472459 # overriding DataFrame method for compat with older pickles (CRS handling)
14481435 if pd.api.types.is_scalar(value) or isinstance(value, BaseGeometry):
14491436 value = [value] * self.shape[0]
14501437 try:
1451 # TODO: remove this use of _crs in 0.12
1452 warn = False
1453 if not (hasattr(self, "geometry") and hasattr(self.geometry, "crs")):
1454 crs = self._crs
1455 warn = True
1456 else:
1457 crs = getattr(self, "crs", None)
1438 crs = getattr(self, "crs", None)
14581439 value = _ensure_geometry(value, crs=crs)
1459 if warn and crs is not None:
1460 warnings.warn(
1461 "Setting geometries to a GeoDataFrame without a geometry "
1462 "column will currently preserve the CRS, if present. "
1463 "This is deprecated, and in the future the CRS will be lost "
1464 "in this case. You can use set_crs(..) on the result to "
1465 "set the CRS manually.",
1466 FutureWarning,
1467 stacklevel=2,
1468 )
14691440 except TypeError:
14701441 warnings.warn("Geometry column does not contain geometry.")
14711442 super().__setitem__(key, value)
20542025 4 326625791 North America United States of America USA 18560000.0 \
20552026 MULTIPOLYGON (((-122.84000 49.00000, -120.0000...
20562027 >>> cities.head()
2057 name geometry
2058 0 Vatican City POINT (12.45339 41.90328)
2059 1 San Marino POINT (12.44177 43.93610)
2060 2 Vaduz POINT (9.51667 47.13372)
2061 3 Luxembourg POINT (6.13000 49.61166)
2062 4 Palikir POINT (158.14997 6.91664)
2028 name geometry
2029 0 Vatican City POINT (12.45339 41.90328)
2030 1 San Marino POINT (12.44177 43.93610)
2031 2 Vaduz POINT (9.51667 47.13372)
2032 3 Lobamba POINT (31.20000 -26.46667)
2033 4 Luxembourg POINT (6.13000 49.61166)
20632034
20642035 >>> cities_w_country_data = cities.sjoin(countries)
20652036 >>> cities_w_country_data.head() # doctest: +SKIP
22522223 >>> capitals = geopandas.read_file(
22532224 ... geopandas.datasets.get_path('naturalearth_cities'))
22542225 >>> capitals.shape
2255 (202, 2)
2226 (243, 2)
22562227
22572228 >>> sa_capitals = capitals.clip(south_america)
22582229 >>> sa_capitals.shape
2259 (12, 2)
2230 (15, 2)
22602231 """
22612232 return geopandas.clip(self, mask=mask, keep_geom_type=keep_geom_type)
22622233
66 from pandas.core.internals import SingleBlockManager
77
88 from pyproj import CRS
9 import shapely
910 from shapely.geometry.base import BaseGeometry
11 from shapely.geometry import GeometryCollection
1012
1113 from geopandas.base import GeoPandasBase, _delegate_property
1214 from geopandas.plotting import plot_series
786788 GeoSeries.isna : detect missing values
787789 """
788790 if value is None:
789 value = BaseGeometry()
791 value = GeometryCollection() if compat.SHAPELY_GE_20 else BaseGeometry()
790792 return super().fillna(value=value, method=method, inplace=inplace, **kwargs)
791793
792794 def __contains__(self, other):
870872 )
871873 index_parts = True
872874
873 if compat.USE_PYGEOS and compat.PYGEOS_GE_09:
874 import pygeos # noqa
875
876 geometries, outer_idx = pygeos.get_parts(
877 self.values.data, return_index=True
878 )
875 if compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_09):
876 if compat.USE_SHAPELY_20:
877 geometries, outer_idx = shapely.get_parts(
878 self.values.data, return_index=True
879 )
880 else:
881 import pygeos # noqa
882
883 geometries, outer_idx = pygeos.get_parts(
884 self.values.data, return_index=True
885 )
879886
880887 if len(outer_idx):
881888 # Generate inner index as a range per value of outer_idx
917924 index = []
918925 geometries = []
919926 for idx, s in self.geometry.items():
920 if s.type.startswith("Multi") or s.type == "GeometryCollection":
927 if s.geom_type.startswith("Multi") or s.geom_type == "GeometryCollection":
921928 geoms = s.geoms
922929 idxs = [(idx, i) for i in range(len(geoms))]
923930 else:
13381345 >>> capitals = geopandas.read_file(
13391346 ... geopandas.datasets.get_path('naturalearth_cities'))
13401347 >>> capitals.shape
1341 (202, 2)
1348 (243, 2)
13421349
13431350 >>> sa_capitals = capitals.geometry.clip(south_america)
13441351 >>> sa_capitals.shape
1345 (12,)
1352 (15,)
13461353 """
13471354 return geopandas.clip(self, mask=mask, keep_geom_type=keep_geom_type)
2525 fiona = None
2626 fiona_env = None
2727 fiona_import_error = None
28 FIONA_GE_19 = False
2829
2930
3031 def _import_fiona():
3132 global fiona
3233 global fiona_env
3334 global fiona_import_error
35 global FIONA_GE_19
3436
3537 if fiona is None:
3638 try:
4749 except ImportError:
4850 fiona_env = None
4951
52 FIONA_GE_19 = Version(Version(fiona.__version__).base_version) >= Version(
53 "1.9.0"
54 )
5055 except ImportError as err:
5156 fiona = False
5257 fiona_import_error = str(err)
195200 installed, otherwise tries "pyogrio".
196201 **kwargs :
197202 Keyword args to be passed to the engine. In case of the "fiona" engine,
198 the keyword arguments are passed to the `open` or `BytesCollection`
199 method in the fiona library when opening the file. For more information
200 on possible keywords, type: ``import fiona; help(fiona.open)``. In
201 case of the "pyogrio" engine, the keyword arguments are passed to
202 `pyogrio.read_dataframe`.
203 the keyword arguments are passed to :func:`fiona.open` or
204 :class:`fiona.collection.BytesCollection` when opening the file.
205 For more information on possible keywords, type:
206 ``import fiona; help(fiona.open)``. In case of the "pyogrio" engine,
207 the keyword arguments are passed to :func:`pyogrio.read_dataframe`.
208
203209
204210 Examples
205211 --------
261267
262268
263269 def _read_file_fiona(
264 path_or_bytes, from_bytes, bbox=None, mask=None, rows=None, **kwargs
270 path_or_bytes, from_bytes, bbox=None, mask=None, rows=None, where=None, **kwargs
265271 ):
272 if where is not None and not FIONA_GE_19:
273 raise NotImplementedError("where requires fiona 1.9+")
274
266275 if not from_bytes:
267276 # Opening a file via URL or file-like-object above automatically detects a
268277 # zipped file. In order to match that behavior, attempt to add a zip scheme
291300
292301 with fiona_env():
293302 with reader(path_or_bytes, **kwargs) as features:
294
295 # In a future Fiona release the crs attribute of features will
296 # no longer be a dict, but will behave like a dict. So this should
297 # be forwards compatible
298 crs = (
299 features.crs["init"]
300 if features.crs and "init" in features.crs
301 else features.crs_wkt
302 )
303 crs = features.crs_wkt
304 # attempt to get EPSG code
305 try:
306 # fiona 1.9+
307 epsg = features.crs.to_epsg(confidence_threshold=100)
308 if epsg is not None:
309 crs = epsg
310 except AttributeError:
311 # fiona <= 1.8
312 try:
313 crs = features.crs["init"]
314 except (TypeError, KeyError):
315 pass
303316
304317 # handle loading the bounding box
305318 if bbox is not None:
313326 mask = mapping(mask.to_crs(crs).unary_union)
314327 elif isinstance(mask, BaseGeometry):
315328 mask = mapping(mask)
329
330 filters = {}
331 if bbox is not None:
332 filters["bbox"] = bbox
333 if mask is not None:
334 filters["mask"] = mask
335 if where is not None:
336 filters["where"] = where
337
316338 # setup the data loading filter
317339 if rows is not None:
318340 if isinstance(rows, int):
319341 rows = slice(rows)
320342 elif not isinstance(rows, slice):
321343 raise TypeError("'rows' must be an integer or a slice.")
322 f_filt = features.filter(
323 rows.start, rows.stop, rows.step, bbox=bbox, mask=mask
324 )
325 elif any((bbox, mask)):
326 f_filt = features.filter(bbox=bbox, mask=mask)
344 f_filt = features.filter(rows.start, rows.stop, rows.step, **filters)
345 elif filters:
346 f_filt = features.filter(**filters)
327347 else:
328348 f_filt = features
329349 # get list of columns
22
33 import pandas as pd
44
5 import shapely
56 import shapely.wkb
67
78 from geopandas import GeoDataFrame
8485
8586 df[geom_col] = geoms = geoms.apply(load_geom)
8687 if crs is None:
87 srid = shapely.geos.lgeos.GEOSGetSRID(geoms.iat[0]._geom)
88 if compat.SHAPELY_GE_20:
89 srid = shapely.get_srid(geoms.iat[0])
90 else:
91 srid = shapely.geos.lgeos.GEOSGetSRID(geoms.iat[0]._geom)
8892 # if no defined SRID in geodatabase, returns SRID of 0
8993 if srid != 0:
9094 crs = "epsg:{}".format(srid)
283287
284288 def _convert_to_ewkb(gdf, geom_name, srid):
285289 """Convert geometries to ewkb."""
286 if compat.USE_PYGEOS:
290 if compat.USE_SHAPELY_20:
291 geoms = shapely.to_wkb(
292 shapely.set_srid(gdf[geom_name].values.data, srid=srid),
293 hex=True,
294 include_srid=True,
295 )
296
297 elif compat.USE_PYGEOS:
287298 from pygeos import set_srid, to_wkb
288299
289300 geoms = to_wkb(
3636 FIONA_GE_1814 = Version(fiona.__version__) >= Version("1.8.14")
3737 # invalid datetime handling
3838 FIONA_GE_1821 = Version(fiona.__version__) >= Version("1.8.21")
39 FIONA_GE_19 = Version(Version(fiona.__version__).base_version) >= Version("1.9.0")
3940 except ImportError:
4041 fiona = False
4142 FIONA_GE_1814 = False
4243 FIONA_GE_1821 = False
44 FIONA_GE_19 = False
4345
4446
4547 PYOGRIO_MARK = pytest.mark.skipif(not pyogrio, reason="pyogrio not installed")
765767 assert gdf.columns.tolist() == ["geometry"]
766768
767769
770 def test_read_file__where_filter(engine):
771 if FIONA_GE_19 or engine == "pyogrio":
772 gdf = geopandas.read_file(
773 geopandas.datasets.get_path("naturalearth_lowres"),
774 where="continent='Africa'",
775 engine=engine,
776 )
777 assert gdf.continent.unique().tolist() == ["Africa"]
778 else:
779 with pytest.raises(NotImplementedError):
780 geopandas.read_file(
781 geopandas.datasets.get_path("naturalearth_lowres"),
782 where="continent='Africa'",
783 engine="fiona",
784 )
785
786
768787 @PYOGRIO_MARK
769788 def test_read_file__columns():
770789 # TODO: this is only support for pyogrio, but we could mimic it for fiona as well
805824 engine=engine,
806825 )
807826 filtered_df_shape = gdf.shape
808 assert filtered_df_shape == (50, 2)
827 assert filtered_df_shape == (57, 2)
809828
810829
811830 def test_read_file_filtered_with_gdf_boundary__mask__polygon(df_nybb, engine):
4747
4848
4949 @pytest.mark.skipif(
50 compat.USE_PYGEOS or (Version(pyproj.__version__) < Version("2.4")),
50 compat.USE_SHAPELY_20
51 or compat.USE_PYGEOS
52 or (Version(pyproj.__version__) < Version("2.4")),
5153 reason=(
52 "pygeos-based unpickling currently only works for pygeos-written files; "
54 "shapely 2.0/pygeos-based unpickling currently only works for "
55 "shapely-2.0/pygeos-written files; "
5356 "old pyproj versions can't read pickles from newer pyproj versions"
5457 ),
5558 )
4747 return geoms, np.arange(len(geoms))
4848
4949 for ix, geom in enumerate(geoms):
50 if geom is not None and geom.type.startswith(prefix) and not geom.is_empty:
50 if geom is not None and geom.geom_type.startswith(prefix) and not geom.is_empty:
5151 for poly in geom.geoms:
5252 components.append(poly)
5353 component_index.append(ix)
434434 expl_color = np.take(color, multiindex, axis=0) if color_given else color
435435 expl_series = geopandas.GeoSeries(geoms)
436436
437 geom_types = expl_series.type
437 geom_types = expl_series.geom_type
438438 poly_idx = np.asarray((geom_types == "Polygon") | (geom_types == "MultiPolygon"))
439439 line_idx = np.asarray(
440440 (geom_types == "LineString")
732732 "Cannot specify 'categories' when column has categorical dtype"
733733 )
734734 categorical = True
735 elif values.dtype is np.dtype("O") or categories:
735 elif (
736 pd.api.types.is_object_dtype(values.dtype)
737 or pd.api.types.is_bool_dtype(values.dtype)
738 or pd.api.types.is_string_dtype(values.dtype)
739 or categories
740 ):
736741 categorical = True
737742
738743 nan_idx = np.asarray(pd.isna(values), dtype="bool")
828833 nan_idx = np.take(nan_idx, multiindex, axis=0)
829834 expl_series = geopandas.GeoSeries(geoms)
830835
831 geom_types = expl_series.type
836 geom_types = expl_series.geom_type
832837 poly_idx = np.asarray((geom_types == "Polygon") | (geom_types == "MultiPolygon"))
833838 line_idx = np.asarray(
834839 (geom_types == "LineString")
1313 Required to comply with _compat.USE_PYGEOS.
1414 The selection order goes PyGEOS > RTree > Error.
1515 """
16 if compat.USE_PYGEOS:
16 if compat.USE_SHAPELY_20 or compat.USE_PYGEOS:
1717 return PyGEOSSTRTreeIndex
1818 if compat.HAS_RTREE:
1919 return RTreeIndex
5454 ----------
5555 geometry : shapely geometry
5656 A single shapely geometry to query against the spatial index.
57 predicate : {None, 'intersects', 'within', 'contains', \
58 'overlaps', 'crosses', 'touches'}, optional
57 predicate : {None, "contains", "contains_properly", "covered_by", "covers", \
58 "crosses", "intersects", "overlaps", "touches", "within"}, optional
5959 If predicate is provided, the input geometry is
6060 tested using the predicate function against each item
6161 in the tree whose extent intersects the envelope of the
117117 geometry : {GeoSeries, GeometryArray, numpy.array of PyGEOS geometries}
118118 Accepts GeoPandas geometry iterables (GeoSeries, GeometryArray)
119119 or a numpy array of PyGEOS geometries.
120 predicate : {None, 'intersects', 'within', 'contains', 'overlaps', \
121 'crosses', 'touches'}, optional
120 predicate : {None, "contains", "contains_properly", "covered_by", "covers", \
121 "crosses", "intersects", "overlaps", "touches", "within"}, optional
122122 If predicate is provided, the input geometries are tested using
123123 the predicate function against each item in the tree whose extent
124124 intersects the envelope of the each input geometry:
436436 "overlaps",
437437 "crosses",
438438 "touches",
439 "covered_by",
439440 "covers",
440441 "contains_properly",
441442 }
501502 if predicate in (
502503 "contains",
503504 "intersects",
505 "covered_by",
504506 "covers",
505507 "contains_properly",
506508 ):
624626 return self.size
625627
626628
627 if compat.HAS_PYGEOS:
629 if compat.SHAPELY_GE_20 or compat.HAS_PYGEOS:
628630
629631 from . import geoseries # noqa
630632 from . import array # noqa
631 import pygeos # noqa
632
633 _PYGEOS_PREDICATES = {p.name for p in pygeos.strtree.BinaryPredicate} | set([None])
633
634 if compat.USE_SHAPELY_20:
635 import shapely as mod # noqa
636
637 _PYGEOS_PREDICATES = {p.name for p in mod.strtree.BinaryPredicate} | set([None])
638 else:
639 import pygeos as mod # noqa
640
641 _PYGEOS_PREDICATES = {p.name for p in mod.strtree.BinaryPredicate} | set([None])
634642
635643 class PyGEOSSTRTreeIndex(BaseSpatialIndex):
636644 """A simple wrapper around pygeos's STRTree.
648656 # https://github.com/pygeos/pygeos/issues/146
649657 # https://github.com/pygeos/pygeos/issues/147
650658 non_empty = geometry.copy()
651 non_empty[pygeos.is_empty(non_empty)] = None
659 non_empty[mod.is_empty(non_empty)] = None
652660 # set empty geometries to None to maintain indexing
653 self._tree = pygeos.STRtree(non_empty)
661 self._tree = mod.STRtree(non_empty)
654662 # store geometries, including empty geometries for user access
655663 self.geometries = geometry.copy()
656664
668676 >>> from shapely.geometry import Point
669677 >>> s = geopandas.GeoSeries([Point(0, 0), Point(1, 1)])
670678 >>> s.sindex.valid_query_predicates # doctest: +SKIP
671 {'contains', 'crosses', 'covered_by', None, 'intersects', 'within', \
672 'touches', 'overlaps', 'contains_properly', 'covers'}
679 {None, "contains", "contains_properly", "covered_by", "covers", \
680 "crosses", "intersects", "overlaps", "touches", "within"}
673681 """
674682 return _PYGEOS_PREDICATES
675683
716724 return geometry.data
717725 elif isinstance(geometry, BaseGeometry):
718726 return array._shapely_to_geom(geometry)
727 elif geometry is None:
728 return None
719729 elif isinstance(geometry, list):
720730 return np.asarray(
721731 [
739749
740750 geometry = self._as_geometry_array(geometry)
741751
742 res = self._tree.query_bulk(geometry, predicate)
752 if compat.USE_SHAPELY_20:
753 res = self._tree.query(geometry, predicate)
754 else:
755 res = self._tree.query_bulk(geometry, predicate)
743756
744757 if sort:
745758 # sort by first array (geometry) and then second (tree)
753766 def nearest(
754767 self, geometry, return_all=True, max_distance=None, return_distance=False
755768 ):
756 if not compat.PYGEOS_GE_010:
757 raise NotImplementedError("sindex.nearest requires pygeos >= 0.10")
769 if not (compat.USE_SHAPELY_20 or compat.PYGEOS_GE_010):
770 raise NotImplementedError(
771 "sindex.nearest requires shapely >= 2.0 or pygeos >= 0.10"
772 )
758773
759774 geometry = self._as_geometry_array(geometry)
760
761 if not return_all and max_distance is None and not return_distance:
762 return self._tree.nearest(geometry)
763
764 result = self._tree.nearest_all(
765 geometry, max_distance=max_distance, return_distance=return_distance
766 )
775 if isinstance(geometry, BaseGeometry) or geometry is None:
776 geometry = [geometry]
777
778 if compat.USE_SHAPELY_20:
779 result = self._tree.query_nearest(
780 geometry,
781 max_distance=max_distance,
782 return_distance=return_distance,
783 all_matches=return_all,
784 )
785 else:
786 if not return_all and max_distance is None and not return_distance:
787 return self._tree.nearest(geometry)
788 result = self._tree.nearest_all(
789 geometry, max_distance=max_distance, return_distance=return_distance
790 )
767791 if return_distance:
768792 indices, distances = result
769793 else:
770794 indices = result
771795
772 if not return_all:
796 if not return_all and not compat.USE_SHAPELY_20:
773797 # first subarray of geometry indices is sorted, so we can use this
774798 # trick to get the first of each index value
775799 mask = np.diff(indices[0, :]).astype("bool")
803827
804828 # need to convert tuple of bounds to a geometry object
805829 if len(coordinates) == 4:
806 indexes = self._tree.query(pygeos.box(*coordinates))
830 indexes = self._tree.query(mod.box(*coordinates))
807831 elif len(coordinates) == 2:
808 indexes = self._tree.query(pygeos.points(*coordinates))
832 indexes = self._tree.query(mod.points(*coordinates))
809833 else:
810834 raise TypeError(
811835 "Invalid coordinates, must be iterable in format "
179179 assert left.index.equals(right.index), "index: %s != %s" % (left.index, right.index)
180180
181181 if check_geom_type:
182 assert (left.type == right.type).all(), "type: %s != %s" % (
183 left.type,
184 right.type,
182 assert (left.geom_type == right.geom_type).all(), "type: %s != %s" % (
183 left.geom_type,
184 right.geom_type,
185185 )
186186
187187 if normalize:
1010 from shapely.geometry.base import CAP_STYLE, JOIN_STYLE
1111 import shapely.wkb
1212 import shapely.wkt
13 from shapely._buildcfg import geos_version
13
14 try:
15 from shapely import geos_version
16 except ImportError:
17 from shapely._buildcfg import geos_version
1418
1519 import geopandas
1620 from geopandas.array import (
141145 # missing values
142146 # TODO(pygeos) does not support empty strings, np.nan, or pd.NA
143147 missing_values = [None]
144 if not compat.USE_PYGEOS:
148 if not (compat.USE_SHAPELY_20 or compat.USE_PYGEOS):
145149 missing_values.extend([b"", np.nan])
146150 missing_values.append(pd.NA)
147151
215219 # missing values
216220 # TODO(pygeos) does not support empty strings, np.nan, or pd.NA
217221 missing_values = [None]
218 if not compat.USE_PYGEOS:
222 if not (compat.USE_SHAPELY_20 or compat.USE_PYGEOS):
219223 missing_values.extend([f(""), np.nan])
220224 missing_values.append(pd.NA)
221225
296296
297297 # geometry column without geometry
298298 df = GeoDataFrame({"geometry": [0, 1]})
299 with pytest.warns(
300 FutureWarning, match="Accessing CRS of a GeoDataFrame without a geometry"
299 with pytest.raises(
300 ValueError,
301 match="Assigning CRS to a GeoDataFrame without an active geometry",
301302 ):
302303 df.crs = 27700
303 with pytest.warns(
304 FutureWarning, match="Accessing CRS of a GeoDataFrame without a geometry"
304 with pytest.raises(
305 AttributeError,
306 match="The CRS attribute of a GeoDataFrame without an active",
305307 ):
306308 assert df.crs == self.osgb
307309
309311 df = GeoDataFrame({"col": range(10)}, geometry=self.arr)
310312 df["geom2"] = df.geometry.centroid
311313 subset = df[["col", "geom2"]]
312 with pytest.warns(
313 FutureWarning, match="Accessing CRS of a GeoDataFrame without a geometry"
314 with pytest.raises(
315 AttributeError,
316 match="The CRS attribute of a GeoDataFrame without an active",
314317 ):
315318 assert subset.crs == self.osgb
316319
354357 arr = from_shapely(self.geoms)
355358 df = GeoDataFrame({"col1": [1, 2], "geometry": arr}, crs=4326)
356359
357 # create a dataframe without geometry column, but currently has cached _crs
360 # override geometry with non geometry
358361 with pytest.warns(UserWarning):
359362 df["geometry"] = 1
360363
361 # assigning a list of geometry object will currently use _crs
362 with pytest.warns(
363 FutureWarning,
364 match="Setting geometries to a GeoDataFrame without a geometry",
365 ):
366 df["geometry"] = self.geoms
367 assert df.crs == self.wgs
364 # assigning a list of geometry object doesn't have cached access to 4326
365 df["geometry"] = self.geoms
366 assert df.crs is None
368367
369368 @pytest.mark.parametrize(
370369 "scalar", [None, Point(0, 0), LineString([(0, 0), (1, 1)])]
0 import warnings
1
02 import numpy as np
13 import pandas as pd
24
288290 )
289291 def test_dissolve_dropna_warn(nybb_polydf):
290292 # No warning with default params
291 with pytest.warns(None) as record:
293 with warnings.catch_warnings(record=True) as record:
292294 nybb_polydf.dissolve()
293295
294296 for r in record:
307309 merged_shapes[("BoroCode", "max")] = [5, 2]
308310 merged_shapes[("BoroName", "count")] = [3, 2]
309311
310 with pytest.warns(None) as record:
312 with warnings.catch_warnings(record=True) as record:
311313 test = nybb_polydf.dissolve(
312314 by="manhattan_bronx",
313315 aggfunc={
255255 def test_bool(self):
256256 df = self.nybb.copy()
257257 df["bool"] = [True, False, True, False, True]
258 m = df.explore("bool")
259 out_str = self._fetch_map_string(m)
260 assert '"__folium_color":"#9edae5","bool":true' in out_str
261 assert '"__folium_color":"#1f77b4","bool":false' in out_str
258 df["bool_extension"] = pd.array([True, False, True, False, True])
259 m1 = df.explore("bool")
260 m2 = df.explore("bool_extension")
261
262 out1_str = self._fetch_map_string(m1)
263 assert '"__folium_color":"#9edae5","bool":true' in out1_str
264 assert '"__folium_color":"#1f77b4","bool":false' in out1_str
265
266 out2_str = self._fetch_map_string(m2)
267 assert '"__folium_color":"#9edae5","bool":true' in out2_str
268 assert '"__folium_color":"#1f77b4","bool":false' in out2_str
269
270 def test_string(self):
271 df = self.nybb.copy()
272 df["string"] = pd.array([1, 2, 3, 4, 5], dtype="string")
273 m = df.explore("string")
274 out_str = self._fetch_map_string(m)
275 assert '"__folium_color":"#9edae5","string":"5"' in out_str
262276
263277 def test_column_values(self):
264278 """
2222 import pytest
2323
2424
25 TEST_NEAREST = compat.PYGEOS_GE_010 and compat.USE_PYGEOS
25 TEST_NEAREST = compat.USE_SHAPELY_20 or (compat.PYGEOS_GE_010 and compat.USE_PYGEOS)
2626 pandas_133 = Version(pd.__version__) == Version("1.3.3")
2727
2828
359359
360360 with pytest.raises(AttributeError, match=msg_no_other_geo_cols):
361361 GeoDataFrame().geometry
362
363 def test_get_geometry_geometry_inactive(self):
364 # https://github.com/geopandas/geopandas/issues/2574
365 df = self.df.assign(geom2=self.df.geometry).set_geometry("geom2")
366 df = df.loc[:, ["BoroName", "geometry"]]
367 assert df._geometry_column_name == "geom2"
368 msg_geo_col_missing = "is not present. "
369 # Check that df.geometry raises if active geometry column is missing,
370 # it should not fall back to column named "geometry"
371 with pytest.raises(AttributeError, match=msg_geo_col_missing):
372 df.geometry
362373
363374 def test_align(self):
364375 df = self.df2
894905 @pytest.mark.parametrize("how", ["left", "inner", "right"])
895906 @pytest.mark.parametrize("predicate", ["intersects", "within", "contains"])
896907 @pytest.mark.skipif(
897 not compat.USE_PYGEOS and not compat.HAS_RTREE,
908 not (compat.USE_PYGEOS and compat.HAS_RTREE and compat.USE_SHAPELY_20),
898909 reason="sjoin needs `rtree` or `pygeos` dependency",
899910 )
900911 def test_sjoin(self, how, predicate):
00 import string
1 import warnings
12
23 import numpy as np
34 from numpy.testing import assert_array_equal
45 from pandas import DataFrame, Index, MultiIndex, Series
56
6 from shapely.geometry import LinearRing, LineString, MultiPoint, Point, Polygon
7 import shapely
8
9 from shapely.geometry import (
10 LinearRing,
11 LineString,
12 MultiPoint,
13 Point,
14 Polygon,
15 MultiPolygon,
16 )
717 from shapely.geometry.collection import GeometryCollection
818 from shapely.ops import unary_union
919 from shapely import wkt
590600 assert_series_equal(res, exp)
591601
592602 @pytest.mark.skipif(
593 not compat.USE_PYGEOS,
603 not (compat.USE_PYGEOS or compat.USE_SHAPELY_20),
594604 reason="covered_by is only implemented for pygeos, not shapely",
595605 )
596606 def test_covered_by(self):
671681 with pytest.warns(UserWarning, match="Geometry is in a geographic CRS"):
672682 self.g4.centroid
673683
684 def test_normalize(self):
685 polygon = Polygon([(0, 0), (1, 1), (0, 1)])
686 linestring = LineString([(0, 0), (1, 1), (1, 0)])
687 point = Point(0, 0)
688 series = GeoSeries([polygon, linestring, point])
689 polygon2 = Polygon([(0, 0), (0, 1), (1, 1)])
690 expected = GeoSeries([polygon2, linestring, point])
691 assert_geoseries_equal(series.normalize(), expected)
692
693 @pytest.mark.skipif(
694 not compat.SHAPELY_GE_18,
695 reason="make_valid keyword introduced in shapely 1.8.0",
696 )
697 def test_make_valid(self):
698 polygon1 = Polygon([(0, 0), (0, 2), (1, 1), (2, 2), (2, 0), (1, 1), (0, 0)])
699 polygon2 = Polygon([(0, 2), (0, 1), (2, 0), (0, 0), (0, 2)])
700 linestring = LineString([(0, 0), (1, 1), (1, 0)])
701 series = GeoSeries([polygon1, polygon2, linestring])
702 out_polygon1 = MultiPolygon(
703 [
704 Polygon([(1, 1), (0, 0), (0, 2), (1, 1)]),
705 Polygon([(2, 0), (1, 1), (2, 2), (2, 0)]),
706 ]
707 )
708 out_polygon2 = GeometryCollection(
709 [Polygon([(2, 0), (0, 0), (0, 1), (2, 0)]), LineString([(0, 2), (0, 1)])]
710 )
711 expected = GeoSeries([out_polygon1, out_polygon2, linestring])
712 assert not series.is_valid.all()
713 result = series.make_valid()
714 assert_geoseries_equal(result, expected)
715 assert result.is_valid.all()
716
717 @pytest.mark.skipif(
718 compat.SHAPELY_GE_18,
719 reason="make_valid keyword introduced in shapely 1.8.0",
720 )
721 def test_make_valid_shapely_pre18(self):
722 s = GeoSeries([Point(1, 1)])
723 with pytest.raises(
724 NotImplementedError,
725 match=f"shapely >= 1.8 or PyGEOS is required, "
726 f"version {shapely.__version__} is installed",
727 ):
728 s.make_valid()
729
674730 def test_convex_hull(self):
675731 # the convex hull of a square should be the same as the square
676732 squares = GeoSeries([self.sq for i in range(3)])
857913 with pytest.warns(UserWarning, match="Geometry is in a geographic CRS"):
858914 self.g4.buffer(1)
859915
860 with pytest.warns(None) as record:
916 with warnings.catch_warnings(record=True) as record:
861917 # do not warn for 0
862918 self.g4.buffer(0)
863919
22 import random
33 import shutil
44 import tempfile
5 import warnings
56
67 import numpy as np
78 from numpy.testing import assert_array_equal
1011
1112 from pyproj import CRS
1213 from shapely.geometry import (
14 GeometryCollection,
1315 LineString,
1416 MultiLineString,
1517 MultiPoint,
120122 # Test that warning is not issued when operating on aligned series
121123 a1, a2 = self.a1.align(self.a2)
122124
123 with pytest.warns(None) as warnings:
125 with warnings.catch_warnings(record=True) as record:
124126 a1.contains(a2) # _series_op, explicitly aligned
125127 self.g1.intersects(self.g2) # _series_op, implicitly aligned
126128 a2.union(a1) # _geo_op, explicitly aligned
127129 self.g2.intersection(self.g1) # _geo_op, implicitly aligned
128130
129 user_warnings = [w for w in warnings if w.category is UserWarning]
131 user_warnings = [w for w in record if w.category is UserWarning]
130132 assert not user_warnings, user_warnings[0].message
131133
132134 def test_geom_equals(self):
383385
384386 @pytest.mark.filterwarnings("ignore::UserWarning")
385387 def test_missing_values():
386 s = GeoSeries([Point(1, 1), None, np.nan, BaseGeometry(), Polygon()])
388 s = GeoSeries([Point(1, 1), None, np.nan, GeometryCollection(), Polygon()])
387389
388390 # construction -> missing values get normalized to None
389391 assert s[1] is None
508510 np.array([], dtype="float64"),
509511 np.array([], dtype="str"),
510512 ]:
511 with pytest.warns(None) as record:
513 with warnings.catch_warnings(record=True) as record:
512514 s = GeoSeries(arr)
513515 assert not record
514516 assert isinstance(s, GeoSeries)
5353 self._check_metadata(res)
5454 exp = GeoDataFrame(pd.concat([pd.DataFrame(self.gdf), pd.DataFrame(self.gdf)]))
5555 assert_geodataframe_equal(exp, res)
56 # check metadata comes from first gdf
57 res4 = pd.concat([self.gdf.set_crs("epsg:4326"), self.gdf], axis=0)
58 # Note: this behaviour potentially does not make sense. If geom cols are
59 # concatenated but have different CRS, then the CRS will be overridden.
60 self._check_metadata(res4, crs="epsg:4326")
6156
6257 # series
6358 res = pd.concat([self.gdf.geometry, self.gdf.geometry])
6459 assert res.shape == (6,)
6560 assert isinstance(res, GeoSeries)
6661 assert isinstance(res.geometry, GeoSeries)
62
63 def test_concat_axis0_crs(self):
64
65 # CRS not set for both GeoDataFrame
66 res = pd.concat([self.gdf, self.gdf])
67 self._check_metadata(res)
68
69 # CRS set for both GeoDataFrame, same CRS
70 res1 = pd.concat([self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4326")])
71 self._check_metadata(res1, crs="epsg:4326")
72
73 # CRS not set for one GeoDataFrame, but set for the other GeoDataFrame
74 with pytest.warns(
75 UserWarning, match=r"CRS not set for some of the concatenation inputs.*"
76 ):
77 res2 = pd.concat([self.gdf, self.gdf.set_crs("epsg:4326")])
78 self._check_metadata(res2, crs="epsg:4326")
79
80 # CRS set for both GeoDataFrame, different CRS
81 with pytest.raises(
82 ValueError, match=r"Cannot determine common CRS for concatenation inputs.*"
83 ):
84 pd.concat([self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4327")])
85
86 # CRS not set for one GeoDataFrame, but set for the other GeoDataFrames,
87 # same CRS
88 with pytest.warns(
89 UserWarning, match=r"CRS not set for some of the concatenation inputs.*"
90 ):
91 res3 = pd.concat(
92 [self.gdf, self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4326")]
93 )
94 self._check_metadata(res3, crs="epsg:4326")
95
96 # CRS not set for one GeoDataFrame, but set for the other GeoDataFrames,
97 # different CRS
98 with pytest.raises(
99 ValueError, match=r"Cannot determine common CRS for concatenation inputs.*"
100 ):
101 pd.concat(
102 [self.gdf, self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4327")]
103 )
67104
68105 def test_concat_axis1(self):
69106
111148 # Note this is not consistent with concat([gdf, gdf], axis=1) where the
112149 # left metadata is set on the result. This is deliberate for now.
113150 assert type(result) is GeoDataFrame
114 self._check_metadata(result, geometry_column_name=None, crs=None)
151 assert result._geometry_column_name is None
115152 assert_index_equal(pd.Index([0, 1]), result.columns)
116153
117154 gseries2.name = "foo"
118155 result2 = pd.concat([gseries2, self.gseries], axis=1)
119156 assert type(result2) is GeoDataFrame
120 self._check_metadata(result2, geometry_column_name=None, crs=None)
157 assert result._geometry_column_name is None
121158 assert_index_equal(pd.Index(["foo", 0]), result2.columns)
301301 assert df.to_csv(index=False) == exp
302302
303303
304 @pytest.mark.filterwarnings(
305 "ignore:Dropping of nuisance columns in DataFrame reductions"
306 )
304307 def test_numerical_operations(s, df):
305
306308 # df methods ignore the geometry column
307309 exp = pd.Series([3, 4], index=["value1", "value2"])
308310 assert_series_equal(df.sum(), exp)
662664 assert result.dtype == "object"
663665
664666
667 def test_df_apply_geometry_dtypes(df):
668 # https://github.com/geopandas/geopandas/issues/1852
669 apply_types = []
670
671 def get_dtypes(srs):
672 apply_types.append((srs.name, type(srs)))
673
674 df["geom2"] = df.geometry
675 df.apply(get_dtypes)
676 expected = [
677 ("geometry", GeoSeries),
678 ("value1", pd.Series),
679 ("value2", pd.Series),
680 ("geom2", GeoSeries),
681 ]
682 assert apply_types == expected
683
684
665685 def test_pivot(df):
666686 # https://github.com/geopandas/geopandas/issues/2057
667687 # pivot failing due to creating a MultiIndex
373373 self.df["cats_ordered"] = pd.Categorical(
374374 ["cat2", "cat1"] * 5, categories=["cat2", "cat1"]
375375 )
376 self.df["bool"] = [False, True] * 5
377 self.df["bool_extension"] = pd.array([False, True] * 5)
378 self.df["cats_string"] = pd.array(["cat1", "cat2"] * 5, dtype="string")
376379
377380 ax1 = self.df.plot("cats_object", legend=True)
378381 ax2 = self.df.plot("cats", legend=True)
380383 ax4 = self.df.plot("singlecat", legend=True)
381384 ax5 = self.df.plot("cats_ordered", legend=True)
382385 ax6 = self.df.plot("nums", categories=[1, 2], legend=True)
386 ax7 = self.df.plot("bool", legend=True)
387 ax8 = self.df.plot("bool_extension", legend=True)
388 ax9 = self.df.plot("cats_string", legend=True)
383389
384390 point_colors1 = ax1.collections[0].get_facecolors()
385 for ax in [ax2, ax3, ax4, ax5, ax6]:
391 for ax in [ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]:
386392 point_colors2 = ax.collections[0].get_facecolors()
387393 np.testing.assert_array_equal(point_colors1[1], point_colors2[1])
388394
389395 legend1 = [x.get_markerfacecolor() for x in ax1.get_legend().get_lines()]
390 for ax in [ax2, ax3, ax4, ax5, ax6]:
396 for ax in [ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]:
391397 legend2 = [x.get_markerfacecolor() for x in ax.get_legend().get_lines()]
392398 np.testing.assert_array_equal(legend1, legend2)
393399
613619
614620 t3 = Polygon([(2, 0), (3, 0), (3, 1)])
615621 df_nan = GeoDataFrame({"geometry": t3, "values": [np.nan]})
616 self.df3 = self.df.append(df_nan)
622 self.df3 = pd.concat([self.df, df_nan])
617623
618624 def test_single_color(self):
619625
881887 color += ["red", "green", "blue"]
882888
883889 self.gdf = GeoDataFrame({"geometry": geom, "color_rgba": color})
884 self.mgdf = self.gdf.dissolve(self.gdf.type)
890 self.mgdf = self.gdf.dissolve(self.gdf.geom_type)
885891
886892 def test_color_single(self):
887893 ax = self.gdf.plot(color=self.gdf["color_rgba"])
17391745 ModuleNotFoundError, match="No module named 'scipy'"
17401746 ):
17411747 self.gdf.plot(kind=kind)
1748 return
17421749 elif kind in _y_kinds:
17431750 kwargs = {"y": "y"}
17441751 elif kind in _xy_kinds:
1616 import pytest
1717 import numpy as np
1818
19 if compat.USE_PYGEOS:
20 import pygeos
19 if compat.USE_SHAPELY_20:
20 import shapely as mod
21 elif compat.USE_PYGEOS:
22 import pygeos as mod
2123
2224
2325 @pytest.mark.skip_no_sindex
7274 s = GeoSeries([t1, t2, sq])
7375 assert s.sindex.size == 3
7476
77 @pytest.mark.filterwarnings("ignore:The series.append method is deprecated")
7578 def test_polygons_append(self):
7679 t1 = Polygon([(0, 0), (1, 0), (1, 1)])
7780 t2 = Polygon([(0, 0), (1, 1), (0, 1)])
697700
698701 # ------------------------- `nearest` tests ------------------------- #
699702 @pytest.mark.skipif(
700 compat.USE_PYGEOS,
703 compat.USE_PYGEOS or compat.USE_SHAPELY_20,
701704 reason=("RTree supports sindex.nearest with different behaviour"),
702705 )
703706 def test_rtree_nearest_warns(self):
708711 df.sindex.nearest((0, 0, 1, 1), num_results=2)
709712
710713 @pytest.mark.skipif(
711 not (compat.USE_PYGEOS and not compat.PYGEOS_GE_010),
714 compat.USE_SHAPELY_20 or not (compat.USE_PYGEOS and not compat.PYGEOS_GE_010),
712715 reason=("PyGEOS < 0.10 does not support sindex.nearest"),
713716 )
714717 def test_pygeos_error(self):
717720 df.sindex.nearest(None)
718721
719722 @pytest.mark.skipif(
720 not (compat.USE_PYGEOS and compat.PYGEOS_GE_010),
723 not (compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_010)),
721724 reason=("PyGEOS >= 0.10 is required to test sindex.nearest"),
722725 )
723726 @pytest.mark.parametrize("return_all", [True, False])
729732 ],
730733 )
731734 def test_nearest_single(self, geometry, expected, return_all):
732 geoms = pygeos.points(np.arange(10), np.arange(10))
735 geoms = mod.points(np.arange(10), np.arange(10))
733736 df = geopandas.GeoDataFrame({"geometry": geoms})
734737
735738 p = Point(geometry)
736739 res = df.sindex.nearest(p, return_all=return_all)
737740 assert_array_equal(res, expected)
738741
739 p = pygeos.points(geometry)
742 p = mod.points(geometry)
740743 res = df.sindex.nearest(p, return_all=return_all)
741744 assert_array_equal(res, expected)
742745
743746 @pytest.mark.skipif(
744 not compat.USE_PYGEOS or not compat.PYGEOS_GE_010,
747 not (compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_010)),
745748 reason=("PyGEOS >= 0.10 is required to test sindex.nearest"),
746749 )
747750 @pytest.mark.parametrize("return_all", [True, False])
753756 ],
754757 )
755758 def test_nearest_multi(self, geometry, expected, return_all):
756 geoms = pygeos.points(np.arange(10), np.arange(10))
759 geoms = mod.points(np.arange(10), np.arange(10))
757760 df = geopandas.GeoDataFrame({"geometry": geoms})
758761
759762 ps = [Point(p) for p in geometry]
760763 res = df.sindex.nearest(ps, return_all=return_all)
761764 assert_array_equal(res, expected)
762765
763 ps = pygeos.points(geometry)
766 ps = mod.points(geometry)
764767 res = df.sindex.nearest(ps, return_all=return_all)
765768 assert_array_equal(res, expected)
766769
774777 assert_array_equal(res, expected)
775778
776779 @pytest.mark.skipif(
777 not compat.USE_PYGEOS or not compat.PYGEOS_GE_010,
780 not (compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_010)),
778781 reason=("PyGEOS >= 0.10 is required to test sindex.nearest"),
779782 )
780783 @pytest.mark.parametrize("return_all", [True, False])
786789 ],
787790 )
788791 def test_nearest_none(self, geometry, expected, return_all):
789 geoms = pygeos.points(np.arange(10), np.arange(10))
792 geoms = mod.points(np.arange(10), np.arange(10))
790793 df = geopandas.GeoDataFrame({"geometry": geoms})
791794
792795 res = df.sindex.nearest(geometry, return_all=return_all)
793796 assert_array_equal(res, expected)
794797
795798 @pytest.mark.skipif(
796 not compat.USE_PYGEOS or not compat.PYGEOS_GE_010,
799 not (compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_010)),
797800 reason=("PyGEOS >= 0.10 is required to test sindex.nearest"),
798801 )
799802 @pytest.mark.parametrize("return_distance", [True, False])
809812 def test_nearest_max_distance(
810813 self, expected, max_distance, return_all, return_distance
811814 ):
812 geoms = pygeos.points(np.arange(10), np.arange(10))
815 geoms = mod.points(np.arange(10), np.arange(10))
813816 df = geopandas.GeoDataFrame({"geometry": geoms})
814817
815818 ps = [Point(0.5, 0.5), Point(0, 10)]
857860 @pytest.mark.parametrize(
858861 "predicate, expected_shape",
859862 [
860 (None, (2, 396)),
861 ("intersects", (2, 172)),
862 ("within", (2, 172)),
863 (None, (2, 470)),
864 ("intersects", (2, 213)),
865 ("within", (2, 213)),
863866 ("contains", (2, 0)),
864867 ("overlaps", (2, 0)),
865868 ("crosses", (2, 0)),
0 import warnings
1
02 import numpy as np
13
24 from shapely.geometry import Point, Polygon
124126
125127 # assert that with `check_crs=False` the assert passes, and also does not
126128 # generate any warning from comparing both geometries with different crs
127 with pytest.warns(None) as record:
129 with warnings.catch_warnings(record=True) as record:
128130 assert_geodataframe_equal(df1, df2, check_crs=False)
129131
130132 assert len(record) == 0
3333 else:
3434 for col in columns:
3535 assert col.lower() in (dfcol.lower() for dfcol in df.columns)
36 assert Series(df.geometry.type).dropna().eq("MultiPolygon").all()
36 assert Series(df.geometry.geom_type).dropna().eq("MultiPolygon").all()
3737
3838
3939 def get_srid(df):
4747 geos_version = "{}.{}.{}".format(*shapely._buildcfg.geos_version)
4848 geos_dir = shapely._buildcfg.geos_library_path
4949 except Exception:
50 geos_version = None
51 geos_dir = None
50 try:
51 from shapely import geos_version_string
52
53 geos_version = geos_version_string
54 geos_dir = None
55 except Exception:
56 geos_version = None
57 geos_dir = None
5258
5359 try:
5460 import fiona
6268 gdal_dir = fiona.env.GDALDataFinder().search()
6369 except Exception:
6470 gdal_dir = None
71
72 if gdal_version is None:
73 try:
74 import pyogrio
75
76 gdal_version = pyogrio.__gdal_version_string__
77 gdal_dir = None
78 except Exception:
79 pass
80 try:
81 # get_gdal_data_path is only available in pyogrio >= 0.4.2
82 from pyogrio import get_gdal_data_path
83
84 gdal_dir = get_gdal_data_path()
85 except Exception:
86 pass
6587
6688 blob = [
6789 ("GEOS", geos_version),
66 """
77 import warnings
88
9 import numpy as np
910 import pandas.api.types
1011 from shapely.geometry import Polygon, MultiPolygon, box
1112
132133 >>> capitals = geopandas.read_file(
133134 ... geopandas.datasets.get_path('naturalearth_cities'))
134135 >>> capitals.shape
135 (202, 2)
136 (243, 2)
136137
137138 >>> sa_capitals = geopandas.clip(capitals, south_america)
138139 >>> sa_capitals.shape
139 (12, 2)
140 (15, 2)
140141 """
141142 if not isinstance(gdf, (GeoDataFrame, GeoSeries)):
142143 raise TypeError(
167168 elif mask_is_list_like:
168169 box_mask = mask
169170 else:
170 box_mask = mask.bounds
171 # Avoid empty tuple returned by .bounds when geometry is empty. A tuple of
172 # all nan values is consistent with the behavior of
173 # {GeoSeries, GeoDataFrame}.total_bounds for empty geometries.
174 # TODO(shapely) can simpely use mask.bounds once relying on Shapely 2.0
175 box_mask = mask.bounds if not mask.is_empty else (np.nan,) * 4
171176 box_gdf = gdf.total_bounds
172177 if not (
173178 ((box_mask[0] <= box_gdf[2]) and (box_gdf[0] <= box_mask[2]))
3434 right = df2.geometry.take(idx2)
3535 right.reset_index(drop=True, inplace=True)
3636 intersections = left.intersection(right)
37 poly_ix = intersections.type.isin(["Polygon", "MultiPolygon"])
37 poly_ix = intersections.geom_type.isin(["Polygon", "MultiPolygon"])
3838 intersections.loc[poly_ix] = intersections[poly_ix].buffer(0)
3939
4040 # only keep actual intersecting geometries
9191 )
9292 new_g.append(new)
9393 differences = GeoSeries(new_g, index=df1.index, crs=df1.crs)
94 poly_ix = differences.type.isin(["Polygon", "MultiPolygon"])
94 poly_ix = differences.geom_type.isin(["Polygon", "MultiPolygon"])
9595 differences.loc[poly_ix] = differences[poly_ix].buffer(0)
9696 geom_diff = differences[~differences.is_empty].copy()
9797 dfdiff = df1[~differences.is_empty].copy()
6262 4 326625791 North America United States of America USA 18560000.0 MULTIPOLY\
6363 GON (((-122.84000 49.00000, -120.0000...
6464 >>> cities.head()
65 name geometry
66 0 Vatican City POINT (12.45339 41.90328)
67 1 San Marino POINT (12.44177 43.93610)
68 2 Vaduz POINT (9.51667 47.13372)
69 3 Luxembourg POINT (6.13000 49.61166)
70 4 Palikir POINT (158.14997 6.91664)
65 name geometry
66 0 Vatican City POINT (12.45339 41.90328)
67 1 San Marino POINT (12.44177 43.93610)
68 2 Vaduz POINT (9.51667 47.13372)
69 3 Lobamba POINT (31.20000 -26.46667)
70 4 Luxembourg POINT (6.13000 49.61166)
7171
7272 >>> cities_w_country_data = geopandas.sjoin(cities, countries)
7373 >>> cities_w_country_data.head() # doctest: +SKIP
359359 how: str,
360360 return_distance: bool,
361361 ):
362 if not (compat.PYGEOS_GE_010 and compat.USE_PYGEOS):
362 if not (compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_010)):
363363 raise NotImplementedError(
364 "Currently, only PyGEOS >= 0.10.0 supports `nearest_all`. "
365 + compat.INSTALL_PYGEOS_ERROR
364 "Currently, only PyGEOS >= 0.10.0 or Shapely >= 2.0 supports "
365 "`nearest_all`. " + compat.INSTALL_PYGEOS_ERROR
366366 )
367367 # use the opposite of the join direction for the index
368368 use_left_as_sindex = how == "right"
449449 multi = buffered_locations.dissolve(by="type").reset_index()
450450 clipped = clip(multi, masks)
451451 assert clipped.geom_type[0] == "Polygon"
452
453
454 @pytest.mark.filterwarnings("ignore:All-NaN slice encountered")
455 @pytest.mark.parametrize(
456 "mask",
457 [
458 Polygon(),
459 (np.nan,) * 4,
460 (np.nan, 0, np.nan, 1),
461 GeoSeries([Polygon(), Polygon()], crs="EPSG:3857"),
462 GeoSeries([Polygon(), Polygon()], crs="EPSG:3857").to_frame(),
463 GeoSeries([], crs="EPSG:3857"),
464 GeoSeries([], crs="EPSG:3857").to_frame(),
465 ],
466 )
467 def test_clip_empty_mask(buffered_locations, mask):
468 """Test that clipping with empty mask returns an empty result."""
469 clipped = clip(buffered_locations, mask)
470 assert_geodataframe_equal(
471 clipped,
472 GeoDataFrame([], columns=["geometry", "type"], crs="EPSG:3857"),
473 check_index_type=False,
474 )
475 clipped = clip(buffered_locations.geometry, mask)
476 assert_geoseries_equal(clipped, GeoSeries([], crs="EPSG:3857"))
1616 import pytest
1717
1818
19 TEST_NEAREST = compat.PYGEOS_GE_010 and compat.USE_PYGEOS
19 TEST_NEAREST = compat.USE_SHAPELY_20 or (compat.PYGEOS_GE_010 and compat.USE_PYGEOS)
2020
2121
2222 pytestmark = pytest.mark.skip_no_sindex
268268 empty = sjoin(not_in, polygons, how="inner", predicate="intersects")
269269 assert empty.empty
270270
271 @pytest.mark.parametrize("predicate", ["intersects", "contains", "within"])
271 @pytest.mark.parametrize(
272 "predicate",
273 [
274 "contains",
275 "contains_properly",
276 "covered_by",
277 "covers",
278 "crosses",
279 "intersects",
280 "touches",
281 "within",
282 ],
283 )
272284 @pytest.mark.parametrize(
273285 "empty",
274286 [
391403 df = sjoin(self.pointdf, self.polydf, how="left")
392404 assert df.shape == (21, 8)
393405 for i, row in df.iterrows():
394 assert row.geometry.type == "Point"
406 assert row.geometry.geom_type == "Point"
395407 assert "pointattr1" in df.columns
396408 assert "BoroCode" in df.columns
397409
402414 assert df.shape == (12, 8)
403415 assert df.shape == df2.shape
404416 for i, row in df.iterrows():
405 assert row.geometry.type == "MultiPolygon"
417 assert row.geometry.geom_type == "MultiPolygon"
406418 for i, row in df2.iterrows():
407 assert row.geometry.type == "MultiPolygon"
419 assert row.geometry.geom_type == "MultiPolygon"
408420
409421 def test_sjoin_inner(self):
410422 df = sjoin(self.pointdf, self.polydf, how="inner")
518530 def test_sjoin_empty_geometries(self):
519531 # https://github.com/geopandas/geopandas/issues/944
520532 empty = GeoDataFrame(geometry=[GeometryCollection()] * 3)
521 df = sjoin(self.pointdf.append(empty), self.polydf, how="left")
533 df = sjoin(pd.concat([self.pointdf, empty]), self.polydf, how="left")
522534 assert df.shape == (24, 8)
523 df2 = sjoin(self.pointdf, self.polydf.append(empty), how="left")
535 df2 = sjoin(self.pointdf, pd.concat([self.polydf, empty]), how="left")
524536 assert df2.shape == (21, 8)
525537
526538 @pytest.mark.parametrize("predicate", ["intersects", "within", "contains"])
558570 cities_with_country = sjoin(
559571 self.cities, countries, how="inner", predicate="intersects"
560572 )
561 assert cities_with_country.shape == (172, 4)
573 assert cities_with_country.shape == (213, 4)
562574
563575
564576 @pytest.mark.skipif(
570582 df2 = geopandas.GeoDataFrame({"geometry": []})
571583 with pytest.raises(
572584 NotImplementedError,
573 match="Currently, only PyGEOS >= 0.10.0 supports `nearest_all`",
585 match="Currently, only PyGEOS >= 0.10.0 or Shapely >= 2.0 supports",
574586 ):
575587 sjoin_nearest(df1, df2)
576588
3131 # must be the same. If there is more than one element,
3232 # they cannot be Multi*, i.e., can't pass in combination of
3333 # Point and MultiPoint... or even just MultiPoint
34 t = x[0].type
35 if not all(g.type == t for g in x):
34 t = x[0].geom_type
35 if not all(g.geom_type == t for g in x):
3636 raise ValueError("Geometry type must be homogeneous")
3737 if len(x) > 1 and t.startswith("Multi"):
3838 raise ValueError("Cannot collect {0}. Must have single geometries".format(t))