Skip to content

Commit 28dcdc1

Browse files
authored
Merge pull request #799 from cgre-aachen/gempy_v2023.1.0-pandas2.0
[WIP] remove inplace for pandas cat
2 parents 3314aed + 2e0b2cd commit 28dcdc1

28 files changed

+145
-98
lines changed

.github/workflows/pytest.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
6161
- name: Run tests with pytest
6262
run: |
63-
pytest
63+
pytest --ignore-glob=/home/runner/work/gempy/gempy/gempy_3/api/test*_gempy3.py
6464
6565
testing_pip:
6666
name: Pip install ${{ matrix.case.os }} py${{ matrix.case.python-version }} ${{ matrix.case.name }}
@@ -108,4 +108,4 @@ jobs:
108108
109109
- name: Run tests with pytest
110110
run: |
111-
pytest
111+
pytest --ignore-glob=/home/runner/work/gempy/gempy/gempy_3/api/test*_gempy3.py

README.md

+11-8
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@
1111
[![DOI](https://zenodo.org/badge/96211155.svg)](https://zenodo.org/badge/latestdoi/96211155)
1212
[![DOCKER](https://img.shields.io/docker/cloud/automated/leguark/gempy.svg)](https://cloud.docker.com/repository/docker/leguark/gempy)
1313

14-
:warning: **Warning: GemPy requires pandas version < 1.4.0. The new pandas release is not compatible with GemPy.
15-
We're actively working on this issue for a future release.
16-
Please make sure to use Pandas version 1.3.x when working with GemPy for the time being.**
17-
18-
**Using theano, GemPy requires numpy version < 1.22.0 as `blas_opt_info` was deprecated in newer numpy versions.**:warning:
1914
## Overview
2015

2116
[GemPy](https://www.gempy.org/) is a Python-based, **open-source geomodeling library**. It is
@@ -40,9 +35,17 @@ the aesara conda installation. Therefore the process would be the following:
4035

4136
For more information, refer to the [installation documentation](https://docs.gempy.org/installation.html).
4237

38+
## Requirements
39+
40+
The following versions are required/strongly recommended for the main dependencies of GemPy (as of June 2023):
41+
- python>=3.10
42+
- pandas>=2.0
43+
- matplotlib>=3.7
44+
- pyvista>=0.39
45+
4346
## Resources
4447

45-
After installation you can either check the [notebook tutorials](https://docs.gempy.org/getting_started/get_started.html#sphx-glr-getting-started-get-started-py)
48+
After installation, you can either check the [notebook tutorials](https://docs.gempy.org/getting_started/get_started.html#sphx-glr-getting-started-get-started-py)
4649
or the [video introduction](https://www.youtube.com/watch?v=n0btC5Zilyc) to get started.
4750

4851
Go to the [documentation site](http://docs.gempy.org/) for further information and enjoy the [tutorials and examples](https://www.gempy.org/tutorials).
@@ -58,8 +61,8 @@ Follow these [guidelines](https://github.com/cgre-aachen/gempy/blob/WIP_readme-u
5861

5962
* de la Varga, M., Schaaf, A., and Wellmann, F. (2019). [GemPy 1.0: open-source stochastic geological modeling and inversion](https://gmd.copernicus.org/articles/12/1/2019/gmd-12-1-2019.pdf), Geosci. Model Dev., 12, 1-32.
6063
* Wellmann, F., & Caumon, G. (2018). [3-D Structural geological models: Concepts, methods, and uncertainties.](https://hal.univ-lorraine.fr/hal-01921494/file/structural_models_for_geophysicsHAL.pdf) In Advances in Geophysics (Vol. 59, pp. 1-121). Elsevier.
61-
* Calcagno, P., Chilès, J. P., Courrioux, G., & Guillen, A. (2008). Geological modelling from field data and geological knowledge: Part I. Modelling method coupling 3D potential-field interpolation and geological rules. Physics of the Earth and Planetary Interiors, 171(1-4), 147-157.
62-
* Lajaunie, C., Courrioux, G., & Manuel, L. (1997). Foliation fields and 3D cartography in geology: principles of a method based on potential interpolation. Mathematical Geology, 29(4), 571-584.
64+
* Calcagno, P., Chilès, J. P., Courrioux, G., & Guillen, A. (2008). [Geological modelling from field data and geological knowledge: Part I. Modelling method coupling 3D potential-field interpolation and geological rules](https://www.sciencedirect.com/science/article/abs/pii/S0031920108001258). Physics of the Earth and Planetary Interiors, 171(1-4), 147-157.
65+
* Lajaunie, C., Courrioux, G., & Manuel, L. (1997). [Foliation fields and 3D cartography in geology: principles of a method based on potential interpolation](https://link.springer.com/article/10.1007/BF02775087). Mathematical Geology, 29(4), 571-584.
6366

6467
## Publications using GemPy
6568

gempy/api_modules/io.py

+15-19
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,8 @@ def _load_surface_points(cat_series, cat_surfaces, geo_model, name, path):
157157
'series': 'category',
158158
'id': 'int64',
159159
'order_series': 'int64'})
160-
geo_model._surface_points.df['surface'].cat.set_categories(cat_surfaces,
161-
inplace=True)
162-
geo_model._surface_points.df['series'].cat.set_categories(cat_series,
163-
inplace=True)
160+
geo_model._surface_points.df['surface'] = geo_model._surface_points.df['surface'].cat.set_categories(cat_surfaces)
161+
geo_model._surface_points.df['series'] = geo_model._surface_points.df['series'].cat.set_categories(cat_series)
164162
# Code to add smooth columns for models saved before gempy 2.0bdev4
165163
try:
166164
geo_model._surface_points.df['smooth']
@@ -183,9 +181,8 @@ def _load_orientations(cat_series, cat_surfaces, geo_model, name, path):
183181
'series': 'category',
184182
'id': 'int64',
185183
'order_series': 'int64'})
186-
geo_model._orientations.df['surface'].cat.set_categories(cat_surfaces,
187-
inplace=True)
188-
geo_model._orientations.df['series'].cat.set_categories(cat_series, inplace=True)
184+
geo_model._orientations.df['surface'] = geo_model._orientations.df['surface'].cat.set_categories(cat_surfaces)
185+
geo_model._orientations.df['series'] = geo_model._orientations.df['series'].cat.set_categories(cat_series)
189186

190187
try:
191188
geo_model._orientations.df['smooth']
@@ -207,7 +204,7 @@ def _load_surfaces(cat_series, geo_model, name, path):
207204
ordered=False)
208205
geo_model._surfaces.sort_surfaces()
209206
geo_model._surfaces.colors.generate_colordict()
210-
geo_model._surfaces.df['series'].cat.set_categories(cat_series, inplace=True)
207+
geo_model._surfaces.df['series'] = geo_model._surfaces.df['series'].cat.set_categories(cat_series)
211208
try:
212209
geo_model._surfaces.df['isActive']
213210
except KeyError:
@@ -228,8 +225,8 @@ def _load_stack(geo_model, name, path):
228225
series_index = pn.CategoricalIndex(geo_model._stack.df.index.values)
229226
# geo_model.series.df.index = pn.CategoricalIndex(series_index)
230227
geo_model._stack.df.index = series_index
231-
geo_model._stack.df['BottomRelation'].cat.set_categories(
232-
['Erosion', 'Onlap', 'Fault'], inplace=True)
228+
geo_model._stack.df['BottomRelation'] = geo_model._stack.df['BottomRelation'].cat.set_categories(
229+
['Erosion', 'Onlap', 'Fault'])
233230
try:
234231
geo_model._stack.df['isActive']
235232
except KeyError:
@@ -259,15 +256,14 @@ def _load_additional_data(geo_model, name, path):
259256
'aesara_optimizer': 'category',
260257
'device': 'category',
261258
'verbosity': object})
262-
geo_model._additional_data.options.df['dtype'].cat.set_categories(
263-
['float32', 'float64'], inplace=True)
264-
geo_model._additional_data.options.df['aesara_optimizer'].cat.set_categories(
265-
['fast_run', 'fast_compile'],
266-
inplace=True)
267-
geo_model._additional_data.options.df['device'].cat.set_categories(
268-
['cpu', 'cuda'], inplace=True)
269-
geo_model._additional_data.options.df['output'].cat.set_categories(
270-
['geology', 'gradients'], inplace=True)
259+
geo_model._additional_data.options.df['dtype'] = geo_model._additional_data.options.df['dtype'].cat.set_categories(
260+
['float32', 'float64'])
261+
geo_model._additional_data.options.df['aesara_optimizer'] = geo_model._additional_data.options.df['aesara_optimizer'].cat.set_categories(
262+
['fast_run', 'fast_compile'])
263+
geo_model._additional_data.options.df['device'] = geo_model._additional_data.options.df['device'].cat.set_categories(
264+
['cpu', 'cuda'])
265+
geo_model._additional_data.options.df['output'] = geo_model._additional_data.options.df['output'].cat.set_categories(
266+
['geology', 'gradients'])
271267
geo_model._additional_data.options.df.loc['values', 'verbosity'] = None
272268

273269

gempy/core/data.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ def __init__(self):
3131
'aesara_optimizer': 'category', 'device': 'category',
3232
'verbosity': object})
3333

34-
self.df['dtype'].cat.set_categories(['float32', 'float64'], inplace=True)
35-
self.df['aesara_optimizer'].cat.set_categories(['fast_run', 'fast_compile'], inplace=True)
36-
self.df['device'].cat.set_categories(['cpu', 'cuda'], inplace=True)
34+
self.df['dtype'] = self.df['dtype'].cat.set_categories(['float32', 'float64'])
35+
self.df['aesara_optimizer'] = self.df['aesara_optimizer'].cat.set_categories(['fast_run', 'fast_compile'])
36+
self.df['device'] = self.df['device'].cat.set_categories(['cpu', 'cuda'])
3737

3838
self.default_options()
3939

gempy/core/data_modules/geometric_data.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def init_dependent_properties(self):
4242
self.df['series'] = 'Default series'
4343
self.df['series'] = self.df['series'].astype('category', copy=True)
4444

45-
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
45+
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)
4646

4747
# id
4848
self.df['id'] = np.nan
@@ -80,12 +80,12 @@ def set_series_categories_from_series(self, series):
8080
Args:
8181
series (:class:`Series`): [s0]
8282
"""
83-
self.df['series'].cat.set_categories(series.df.index, inplace=True)
83+
self.df['series'] = self.df['series'].cat.set_categories(series.df.index)
8484
return True
8585

8686
def update_series_category(self):
8787
"""Update the series categorical columns with the series categories of the :class:`Surfaces` attribute."""
88-
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
88+
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)
8989

9090
return True
9191

@@ -98,7 +98,7 @@ def set_surface_categories_from_surfaces(self, surfaces: Surfaces):
9898
9999
"""
100100

101-
self.df['surface'].cat.set_categories(surfaces.df['surface'], inplace=True)
101+
self.df['surface'] = self.df['surface'].cat.set_categories(surfaces.df['surface'])
102102
return True
103103

104104
# @_setdoc_pro(Series.__doc__)
@@ -126,7 +126,7 @@ def map_data_from_series(self, series, attribute: str, idx=None):
126126

127127
if type(self.df['order_series'].dtype) is pn.CategoricalDtype:
128128

129-
self.df['order_series'].cat.remove_unused_categories(inplace=True)
129+
self.df['order_series'] = self.df['order_series'].cat.remove_unused_categories()
130130
return self
131131

132132
@_setdoc_pro(Surfaces.__doc__)
@@ -165,7 +165,7 @@ def _add_surface_to_list_from_new_surface_points_or_orientations(self, idx, surf
165165
# Check is self.df['surface'] is a category
166166
if not isinstance(self.df['surface'].dtype, pd.CategoricalDtype):
167167
self.df['surface'] = self.df['surface'].astype('category', copy=True)
168-
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
168+
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)
169169

170170
# Check if elements in surface are categories in self.df['surface'] and if not add them
171171
# for s in surface:

gempy/core/data_modules/orientations.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def set_orientations(self, coord: np.ndarray = None, pole_vector: np.ndarray = N
6666
'azimuth', 'polarity', 'surface'], dtype=float)
6767

6868
self.df['surface'] = self.df['surface'].astype('category', copy=True)
69-
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
69+
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)
7070

7171
pole_vector = check_for_nans(pole_vector)
7272
orientation = check_for_nans(orientation)
@@ -94,7 +94,7 @@ def set_orientations(self, coord: np.ndarray = None, pole_vector: np.ndarray = N
9494
'this point. Check previous condition')
9595

9696
self.df['surface'] = self.df['surface'].astype('category', copy=True)
97-
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
97+
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)
9898

9999
self.init_dependent_properties()
100100

@@ -161,10 +161,10 @@ def add_orientation(self, x, y, z, surface: list[str] | str, pole_vector: Union[
161161

162162
# create new pandas categories from slef.df.['surface']
163163
self.df['surface'] = self.df['surface'].astype('category', copy=True)
164-
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
164+
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)
165165

166166
self.df['series'] = self.df['series'].astype('category', copy=True)
167-
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
167+
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)
168168

169169
self.map_data_from_surfaces(self.surfaces, 'series', idx=idx)
170170
self.map_data_from_surfaces(self.surfaces, 'id', idx=idx)

gempy/core/data_modules/surface_points.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def set_surface_points(self, coord: np.ndarray = None, surface: list = None):
6363
self.df['surface'] = surface
6464

6565
self.df['surface'] = self.df['surface'].astype('category', copy=True)
66-
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
66+
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)
6767

6868
# Choose types
6969
self.init_dependent_properties()
@@ -128,10 +128,10 @@ def add_surface_points(self, x: Union[float, np.ndarray], y: Union[float, np.nda
128128
self.df.loc[idx, ['smooth']] = 1e-6
129129

130130
self.df['surface'] = self.df['surface'].astype('category', copy=True)
131-
self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values, inplace=True)
131+
self.df['surface'] = self.df['surface'].cat.set_categories(self.surfaces.df['surface'].values)
132132

133133
self.df['series'] = self.df['series'].astype('category', copy=True)
134-
self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories, inplace=True)
134+
self.df['series'] = self.df['series'].cat.set_categories(self.surfaces.df['series'].cat.categories)
135135

136136
self.map_data_from_surfaces(self.surfaces, 'series', idx=idx)
137137
self.map_data_from_surfaces(self.surfaces, 'id', idx=idx)

gempy/core/model.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -621,9 +621,8 @@ def modify_order_features(self, new_value: int, idx: str):
621621
"""
622622
self._stack.modify_order_series(new_value, idx)
623623

624-
self._surfaces.df['series'].cat.reorder_categories(
625-
np.asarray(self._stack.df.index),
626-
ordered=False, inplace=True)
624+
self._surfaces.df['series'] = self._surfaces.df['series'].cat.reorder_categories(
625+
np.asarray(self._stack.df.index), ordered=False)
627626

628627
self._surfaces.sort_surfaces()
629628
self._surfaces.set_basement()

gempy/core/surfaces.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def __init__(self, series, surface_names=None, values_array=None, properties_nam
4848
if (np.array(sys.version_info[:2]) <= np.array([3, 6])).all():
4949
self.df: pn.DataFrame
5050

51-
self.df['series'].cat.add_categories(['Default series'], inplace=True)
51+
self.df['series'] = self.df['series'].cat.add_categories(['Default series'])
5252
if surface_names is not None:
5353
self.set_surfaces_names(surface_names)
5454

@@ -64,7 +64,7 @@ def __repr__(self):
6464
def _repr_html_(self):
6565
c_ = self.df.columns[~(self.df.columns.isin(self._columns_vis_drop))]
6666

67-
return self.df[c_].style.applymap(self.background_color, subset=['color']).render()
67+
return self.df[c_].style.applymap(self.background_color, subset=['color']).to_html()
6868

6969
@property
7070
def properties_val(self):
@@ -312,7 +312,7 @@ def map_series(self, mapping_object: Union[dict, pn.DataFrame] = None):
312312
"""
313313

314314
# Updating surfaces['series'] categories
315-
self.df['series'].cat.set_categories(self.series.df.index, inplace=True)
315+
self.df['series'] = self.df['series'].cat.set_categories(self.series.df.index)
316316
# TODO Fixing this. It is overriding the formations already mapped
317317
if mapping_object is not None:
318318
# If none is passed and series exists we will take the name of the first series as a default
@@ -326,8 +326,8 @@ def map_series(self, mapping_object: Union[dict, pn.DataFrame] = None):
326326
s.append(k)
327327
f.append(form)
328328

329-
new_series_mapping = pn.DataFrame([pn.Categorical(s, self.series.df.index)],
330-
f, columns=['series'])
329+
new_series_mapping = pn.DataFrame(list(zip(pn.Categorical(s, self.series.df.index))),
330+
index=f, columns=['series'])
331331

332332
elif isinstance(mapping_object, pn.Categorical):
333333
# This condition is for the case we have surface on the index and in 'series' the category
@@ -351,6 +351,7 @@ def map_series(self, mapping_object: Union[dict, pn.DataFrame] = None):
351351
self.reset_order_surfaces()
352352
self.sort_surfaces()
353353
self.set_basement()
354+
354355
return self
355356

356357
# endregion

gempy_3/api/test_api/test_model_gempy2_to_gempy3_basic.py renamed to gempy_3/api/test_api/test_basic_model_gempy2_to_gempy3.py

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
11
import os
2+
import pytest
3+
4+
#IN_GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true"
5+
IN_GITHUB_ACTIONS = True
6+
27
import gempy as gp
3-
import gempy_engine
48
from gempy import Project
59
from gempy.plot.vista import GemPyToVista
610
from gempy_3.api.gp2_to_gp3_input import gempy_project_to_interpolation_input, gempy_project_to_input_data_descriptor, gempy_project_to_interpolation_options
711
from gempy_3.api.gp3_to_gp2_output import set_gp3_solutions_to_gp2_solution
812
from gempy_3.api.test_api._gp2togp3_test_utils import create_interpolator, load_model, map_sequential_pile
9-
from gempy_engine.config import AvailableBackends
10-
from gempy_engine.core.backend_tensor import BackendTensor
11-
from gempy_engine.core.data import InterpolationOptions
12-
from gempy_engine.core.data.input_data_descriptor import InputDataDescriptor
13-
from gempy_engine.core.data.interpolation_input import InterpolationInput
14-
from gempy_engine.core.data.solutions import Solutions
13+
14+
if not IN_GITHUB_ACTIONS:
15+
import gempy_engine
16+
from gempy_engine.config import AvailableBackends
17+
from gempy_engine.core.backend_tensor import BackendTensor
18+
from gempy_engine.core.data import InterpolationOptions
19+
from gempy_engine.core.data.input_data_descriptor import InputDataDescriptor
20+
from gempy_engine.core.data.interpolation_input import InterpolationInput
21+
from gempy_engine.core.data.solutions import Solutions
1522

1623
input_path = os.path.dirname(__file__) + '/../../../test/input_data'
1724
import sys # These two lines are necessary only if GemPy is not installed
1825

1926
sys.path.append("../..")
2027

21-
28+
@pytest.mark.skipif(IN_GITHUB_ACTIONS, reason="Only runs once gempy 3 is published.")
2229
def test_set_gempy3_gempy2_bridge():
2330
"""
2431
This test is based on gempy/test/test_core/test_model.py:test_compute_model

0 commit comments

Comments
 (0)