From 1f9c0e393bca3259499ef313968db07009747d96 Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Fri, 10 Jan 2025 18:18:54 -0500 Subject: [PATCH] chore(dependencies/docs): update conda env, fix notebooks (#2414) The `environment.yml` was missing a few optional/developer dependencies we've recently added to `pyproject.toml`. Bring the former into sync with the latter (and list packages in the same order). With luck, conda will eventually be able to consume `pyproject.toml` files, and we can remove `environment.yml`. More info at issue 10633 on the conda repo (not linking to avoid the crossref showing up there). There were some old pycharm cell format comments in the notebook scripts which jupytext didn't like, remove them. This should close #2253. To avoid similar situations in the future, don't skip notebooks due to missing dependencies in CI. We did this for convenient local testing, so tests can run without all optional dependencies, but CI should be strict. --- .docs/Notebooks/array_output_tutorial.py | 16 ---- .../Notebooks/mt3dms_sft_lkt_uzt_tutorial.py | 1 - .docs/Notebooks/plot_cross_section_example.py | 61 ------------- .docs/Notebooks/plot_map_view_example.py | 91 ++----------------- .docs/Notebooks/seawat_henry_example.py | 1 - .docs/Notebooks/shapefile_feature_examples.py | 3 - autotest/conftest.py | 9 -- autotest/test_notebooks.py | 7 +- etc/environment.yml | 25 +++-- 9 files changed, 28 insertions(+), 186 deletions(-) diff --git a/.docs/Notebooks/array_output_tutorial.py b/.docs/Notebooks/array_output_tutorial.py index 641cf66c47..e4941f275b 100644 --- a/.docs/Notebooks/array_output_tutorial.py +++ b/.docs/Notebooks/array_output_tutorial.py @@ -17,16 +17,13 @@ # - name: Jeremy White # --- -# + [markdown] pycharm={"name": "#%% md\n"} # # Formatting ASCII output arrays # # ### Configuring numeric arrays written by FloPy -# + [markdown] pycharm={"name": "#%% md\n"} # load and run the Freyberg model -# + pycharm={"name": "#%%\n"} import os import sys from pathlib import Path @@ -111,26 +108,20 @@ errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + [markdown] pycharm={"name": "#%% md\n"} # Each ``Util2d`` instance now has a ```.format``` attribute, which is an ```ArrayFormat``` instance: -# + pycharm={"name": "#%%\n"} print(ml.lpf.hk[0].format) -# + [markdown] pycharm={"name": "#%% md\n"} # The ```ArrayFormat``` class exposes each of the attributes seen in the ```ArrayFormat.___str___()``` call. ```ArrayFormat``` also exposes ``.fortran``, ``.py`` and ``.numpy`` atrributes, which are the respective format descriptors: -# + pycharm={"name": "#%%\n"} print(ml.dis.botm[0].format.fortran) print(ml.dis.botm[0].format.py) print(ml.dis.botm[0].format.numpy) -# + [markdown] pycharm={"name": "#%% md\n"} # #### (re)-setting ```.format``` # # We can reset the format using a standard fortran type format descriptor -# + pycharm={"name": "#%%\n"} ml.dis.botm[0].format.free = False ml.dis.botm[0].format.fortran = "(20f10.4)" print(ml.dis.botm[0].format.fortran) @@ -147,25 +138,19 @@ else: raise ValueError("Failed to run.") -# + [markdown] pycharm={"name": "#%% md\n"} # Let's load the model we just wrote and check that the desired ```botm[0].format``` was used: -# + pycharm={"name": "#%%\n"} ml1 = flopy.modflow.Modflow.load("freyberg.nam", model_ws=modelpth) print(ml1.dis.botm[0].format) -# + [markdown] pycharm={"name": "#%% md\n"} # We can also reset individual format components (we can also generate some warnings): -# + pycharm={"name": "#%%\n"} ml.dis.botm[0].format.width = 9 ml.dis.botm[0].format.decimal = 1 print(ml1.dis.botm[0].format) -# + [markdown] pycharm={"name": "#%% md\n"} # We can also select ``free`` format. Note that setting to free format resets the format attributes to the default, max precision: -# + pycharm={"name": "#%%\n"} ml.dis.botm[0].format.free = True print(ml1.dis.botm[0].format) # - @@ -178,6 +163,5 @@ else: raise ValueError("Failed to run.") -# + pycharm={"name": "#%%\n"} ml1 = flopy.modflow.Modflow.load("freyberg.nam", model_ws=modelpth) print(ml1.dis.botm[0].format) diff --git a/.docs/Notebooks/mt3dms_sft_lkt_uzt_tutorial.py b/.docs/Notebooks/mt3dms_sft_lkt_uzt_tutorial.py index 35fdc2d670..20f64685c2 100644 --- a/.docs/Notebooks/mt3dms_sft_lkt_uzt_tutorial.py +++ b/.docs/Notebooks/mt3dms_sft_lkt_uzt_tutorial.py @@ -841,7 +841,6 @@ # #### Write the MT3D-USGS input files for inspecting and running -# + pycharm={"name": "#%%\n"} mf.write_input() mt.write_input() diff --git a/.docs/Notebooks/plot_cross_section_example.py b/.docs/Notebooks/plot_cross_section_example.py index 68f4c61516..75df9a323b 100644 --- a/.docs/Notebooks/plot_cross_section_example.py +++ b/.docs/Notebooks/plot_cross_section_example.py @@ -17,14 +17,12 @@ # - name: Scott Paulinski # --- -# + [markdown] pycharm={"name": "#%% md\n"} # # Making Cross Sections of Your Model # This notebook demonstrates the cross sectional mapping capabilities of FloPy. It demonstrates these capabilities by loading and running existing models and then showing how the `PlotCrossSection` object and its methods can be used to make nice plots of the model grid, boundary conditions, model results, shape files, etc. # # ### Mapping is demonstrated for MODFLOW-2005 and MODFLOW-6 models in this notebook -# + pycharm={"name": "#%%\n"} import os import sys from pathlib import Path @@ -45,7 +43,6 @@ print(f"matplotlib version: {mpl.__version__}") print(f"flopy version: {flopy.__version__}") -# + pycharm={"name": "#%%\n"} # Set names of the MODFLOW exes # assumes that the executable is in users path statement v2005 = "mf2005" @@ -89,7 +86,6 @@ tempdir = TemporaryDirectory() modelpth = Path(tempdir.name) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Load and Run an Existing MODFLOW-2005 Model # A model called the "Freyberg Model" is located in the loadpth folder. In the following code block, we load that model, then change into a new workspace (modelpth) where we recreate and run the model. For this to work properly, the MODFLOW-2005 executable (mf2005) must be in the path. We verify that it worked correctly by checking for the presence of freyberg.hds and freyberg.cbc. @@ -111,12 +107,10 @@ errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Creating a Cross-Section of the Model Grid # # Now that we have a model, we can use the FloPy plotting utilities to make cross-sections. We'll start by making a Map to show the model grid and basic boundary conditions. Then we'll begin making a cross section using the `PlotCrossSection` class and the `plot_grid()` method of that class. -# + pycharm={"name": "#%%\n"} # let's take a look at our grid before making a cross section fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") @@ -126,10 +120,8 @@ riv = mapview.plot_bc("RIV") linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # Next we will make a cross-section of the model grid at column 6. -# + pycharm={"name": "#%%\n"} # First step is to set up the plot fig = plt.figure(figsize=(15, 5)) ax = fig.add_subplot(1, 1, 1) @@ -143,12 +135,10 @@ linecollection = xsect.plot_grid() t = ax.set_title("Column 6 Cross-Section - Model Grid") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Ploting Ibound # # The `plot_ibound()` method can be used to plot the boundary conditions contained in the ibound arrray, which is part of the MODFLOW Basic Package. The `plot_ibound()` method returns a matplotlib PatchCollection object (matplotlib.collections.PatchCollection). If you are familiar with the matplotlib collections, then this may be important to you, but if not, then don't worry about the return objects of these plotting function. -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(15, 5)) ax = fig.add_subplot(1, 1, 1) @@ -157,7 +147,6 @@ linecollection = xsect.plot_grid() t = ax.set_title("Column 6 Cross-Section with IBOUND Boundary Conditions") -# + pycharm={"name": "#%%\n"} # Or we could change the colors! fig = plt.figure(figsize=(15, 5)) ax = fig.add_subplot(1, 1, 1) @@ -167,7 +156,6 @@ linecollection = xsect.plot_grid(color="green") t = ax.set_title("Column 6 Cross-Section with IBOUND Boundary Conditions") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Boundary Conditions # The `plot_bc()` method can be used to plot boundary conditions on a cross section. It is setup to use the following dictionary to assign colors, however, these colors can be changed in the method call. # @@ -178,7 +166,6 @@ # # Here, we plot the location of well cells in column 6. -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(15, 5)) ax = fig.add_subplot(1, 1, 1) @@ -188,12 +175,10 @@ linecollection = xsect.plot_grid() t = ax.set_title("Column 6 Cross-Section with Boundary Conditions") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting an Array # # `PlotCrossSection` has a `plot_array()` method. The `plot_array()` method will only accept 3D arrays for structured grids. -# + pycharm={"name": "#%%\n"} # Create a random array and plot it a = np.random.random((ml.dis.nlay, ml.dis.nrow, ml.dis.ncol)) @@ -206,7 +191,6 @@ t = ax.set_title("Column 6 Cross-Section with Random Data") cb = plt.colorbar(csa, shrink=0.75) -# + pycharm={"name": "#%%\n"} # plot the horizontal hydraulic conductivities a = ml.lpf.hk.array @@ -219,12 +203,10 @@ t = ax.set_title("Column 6 Cross-Section with Horizontal hydraulic conductivity") cb = plt.colorbar(csa, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Contouring an Array # # `PlotCrossSection` also has a `contour_array()` method. It also accepts a 3D array for structured grids. -# + pycharm={"name": "#%%\n"} # plot the horizontal hydraulic conductivities a = ml.lpf.hk.array @@ -239,14 +221,12 @@ ) cb = plt.colorbar(contour_set, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Heads # # We can easily plot results from the simulation by extracting heads using `flopy.utils.HeadFile`. # # The head can be passed into the `plot_array()` and `contour_array()` using the `head=` keyword argument to fix the top of the colored patch and contour lines at the top of the water table in each cell, respectively. -# + pycharm={"name": "#%%\n"} fname = os.path.join(str(modelpth), "freyberg.hds") hdobj = flopy.utils.HeadFile(fname) head = hdobj.get_data() @@ -261,7 +241,6 @@ linecollection = xsect.plot_grid() cb = plt.colorbar(pc, shrink=0.75) -# + pycharm={"name": "#%%\n"} # contour array on top of heads levels = np.arange(17, 26, 1) @@ -283,12 +262,10 @@ cb = plt.colorbar(pc, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting a surface on the cross section # # The `plot_surface()` method allows the user to plot a surface along the cross section. Here is a short example using head data. -# + pycharm={"name": "#%%\n"} levels = np.arange(10, 30, 0.5) fig = plt.figure(figsize=(18, 5)) @@ -307,12 +284,10 @@ plt.title("contour_array() and plot_surface()") cb = plt.colorbar(ct, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting discharge vectors # # `PlotCrossSection` has a `plot_vector()` method, which takes `qx`, `qy`, and `qz` vector arrays (ex. specific discharge or flow across a cell faces). The flow array values can be extracted from the cell by cell flow file using the `flopy.utils.CellBudgetFile` object as shown below. Once they are extracted, they either be can be passed to the `plot_vector()` method or they can be post processed into specific discharge using `postprocessing.get_specific_discharge`. Note that `get_specific_discharge()` also takes the head array as an argument. The head array is used by `get_specific_discharge()` to convert the volumetric flow in dimensions of $L^3/T$ to specific discharge in dimensions of $L/T$ and to plot the specific discharge in the center of each saturated cell. For this problem, there is no 'FLOW LOWER FACE' array since the Freyberg Model is a one layer model. -# + pycharm={"name": "#%%\n"} fname = os.path.join(str(modelpth), "freyberg.cbc") cbb = flopy.utils.CellBudgetFile(fname) frf = cbb.get_data(text="FLOW RIGHT FACE")[0] @@ -321,7 +296,6 @@ (frf, fff, None), ml, head=head ) -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(18, 5)) ax = fig.add_subplot(1, 1, 1) @@ -347,7 +321,6 @@ cb = plt.colorbar(csa, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting a cross section from Shapefile data # # A shapefile can be used to define the vertices for a instance of the `PlotCrossSection` class. The function `flopy.plot.plotutil.shapefile_get_vertices()` will return a list of vertices for each polyline in a shapefile. @@ -408,7 +381,6 @@ copytree(data_path / sim_name / "gis", modelpth / "gis") -# + pycharm={"name": "#%%\n"} # Setup the figure and PlotMapView. Show a very faint map of ibound and # model grid by specifying a transparency alpha value. @@ -443,12 +415,10 @@ quadmesh = mapview.plot_ibound(alpha=0.1) linecollection = mapview.plot_grid(alpha=0.1) -# + [markdown] pycharm={"name": "#%% md\n"} # Now let's make a cross section based on this arbitrary cross-sectional line. We can load the cross sectional line vertices using `flopy.plot.plotutil.shapefile_get_vertices()` # # **Note**: in previous examples we passed `line={'column', 5}` to plot a cross section along a column. In this example we pass vertex information into `PlotCrossSection` using `line={'line', line[0]}` where `line[0]` is a list of vertices. -# + pycharm={"name": "#%%\n"} # get the vertices for cross-section lines in a shapefile fpth = os.path.join(modelpth, "gis", "cross_section_rotate14") line = flopy.plot.plotutil.shapefile_get_vertices(fpth) @@ -465,14 +435,12 @@ linecollection = xsect.plot_grid(lw=0.5) cb = fig.colorbar(csa, ax=ax, shrink=0.5) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting geographic coordinates on the x-axis using the `PlotCrossSection` class # # The default cross section plotting method plots cells with regard to their intersection distance along the cross sectional line defined by the user. While this method is perfectly acceptable and in many cases may be preferred for plotting arbitrary cross sections, a flag has been added to plot based on geographic coordinates. # # The flag `geographic_coords` defaults to `False` which maintains FloPy's previous method of plotting cross sections. -# + pycharm={"name": "#%%\n"} # get the vertices for cross-section lines in a shapefile fpth = os.path.join(modelpth, "gis", "cross_section_rotate14") line = flopy.plot.plotutil.shapefile_get_vertices(fpth) @@ -491,7 +459,6 @@ linecollection = xsect.plot_grid(lw=0.5) cb = fig.colorbar(csa, ax=ax, shrink=0.5) -# + [markdown] pycharm={"name": "#%% md\n"} # ## Plotting Cross Sections with MODFLOW-6 models # # `PlotCrossSection` has support for MODFLOW-6 models and operates in the same fashion for Structured Grids, Vertex Grids, and Unstructured Grids. Here is a short example on how to plot with MODFLOW-6 structured grids using a version of the Freyberg model created for MODFLOW-6| @@ -551,12 +518,10 @@ errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting boundary conditions and arrays # # This works the same as modflow-2005, however the simulation object can host a number of modflow-6 models so we need to grab a model before attempting to plot with `PlotCrossSection` -# + pycharm={"name": "#%%\n"} # get the modflow-6 model we want to plot ml6 = sim.get_model("freyberg") @@ -582,12 +547,10 @@ t = ax.set_title("Column 6 Cross-Section with Horizontal hydraulic conductivity") cb = plt.colorbar(csa, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting specific discharge with a MODFLOW-6 model # # MODFLOW-6 includes a the PLOT_SPECIFIC_DISCHARGE flag in the NPF package to calculate and store discharge vectors for easy plotting. The `postprocessing.get_specific_discharge()` method will preprocess the data into vectors and `PlotCrossSection` has the `plot_vector()` method to use this data. The specific discharge array is stored in the cell budget file. -# + pycharm={"name": "#%%\n"} # get the head from the head file head_file = os.path.join(modelpth, "freyberg.hds") hds = flopy.utils.HeadFile(head_file) @@ -624,13 +587,11 @@ cb = plt.colorbar(csa, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ## Vertex cross section plotting with MODFLOW-6 (DISV) # # FloPy fully supports vertex discretization (DISV) plotting through the `PlotCrossSection` class. The method calls are identical to the ones presented previously for Structured discretization (DIS) and the same matplotlib keyword arguments are supported. Let's run through an example using a vertex model grid. -# + pycharm={"name": "#%%\n"} # build and run vertex model grid demo problem def run_vertex_grid_example(ws): """load and run vertex grid example""" @@ -932,7 +893,6 @@ def run_vertex_grid_example(ws): errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + pycharm={"name": "#%%\n"} # load the simulation and get the model vertex_sim_name = "mfsim.nam" vertex_sim = flopy.mf6.MFSimulation.load( @@ -943,13 +903,11 @@ def run_vertex_grid_example(ws): ) vertex_ml6 = vertex_sim.get_model("mp7p2") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting a line based cross section through the model grid # # Because a `VertexGrid` has no row or column number, the cross-section line must be defined explicitly. This is done by passing a dictionary to the `line` parameter with key `line` — the value may be an array-like of 2 or more points, e.g. `{"line": [(x0, y0), (x1, y1), ...]}`, or a `flopy.utils.geometry.LineString` or `shapely.geometry.LineString`. Below we show an example of setting up a cross-section line with a MODFLOW-6 DISV model. # -# + pycharm={"name": "#%%\n"} line = np.array([(4700, 0), (4700, 5000), (7250, 10500)]) # Let's plot the model grid in map view to look at it @@ -964,10 +922,8 @@ def run_vertex_grid_example(ws): # plot the line over the model grid lc = plt.plot(line.T[0], line.T[1], "r--", lw=2) -# + [markdown] pycharm={"name": "#%% md\n"} # Now we can plot a cross section of the model grid defined by this line -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(15, 5)) ax = fig.add_subplot(1, 1, 1) @@ -980,12 +936,10 @@ def run_vertex_grid_example(ws): linecollection = xsect.plot_grid() t = ax.set_title("Column 6 Cross-Section - Model Grid") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Arrays and Contouring with Vertex Model grids # # `PlotCrossSection` allows the user to plot arrays and contour with DISV based discretization. The `plot_array()` method is called in the same way as using a structured grid. The only difference is that `PlotCrossSection` builds a matplotlib patch collection for Vertex based grids. -# + pycharm={"name": "#%%\n"} # get the head output for stress period 1 from the modflow6 head file head = flopy.utils.HeadFile(os.path.join(modelpth, "mp7p2.hds")) hdata = head.get_alldata()[0, :, :, :] @@ -999,10 +953,8 @@ def run_vertex_grid_example(ws): line_collection = xsect.plot_grid() cb = plt.colorbar(patch_collection, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # The `contour_array()` method operates in the same way as the sturctured example. -# + pycharm={"name": "#%%\n"} levels = np.arange(329, 337, 1) fig = plt.figure(figsize=(18, 5)) @@ -1018,13 +970,11 @@ def run_vertex_grid_example(ws): cb = plt.colorbar(patch_collection, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting specific discharge vectors for DISV # MODFLOW-6 includes a the PLOT_SPECIFIC_DISCHARGE flag in the NPF package to calculate and store discharge vectors for easy plotting.The `postprocessing.get_specific_discharge()` method will preprocess the data into vectors and `PlotCrossSection` has the `plot_vector()` method to use this data. The specific discharge array is stored in the cell budget file. # # **Note**: When plotting specific discharge, an arbitrary cross section cannot be used. The cross sectional line must be orthogonal to the model grid -# + pycharm={"name": "#%%\n"} # define and plot our orthogonal line line = np.array([(0, 4700), (10000, 4700)]) @@ -1040,7 +990,6 @@ def run_vertex_grid_example(ws): # plot the line over the model grid lc = plt.plot(line.T[0], line.T[1], "r--", lw=2) -# + pycharm={"name": "#%%\n"} # plot specific discharge on cross section cbb = flopy.utils.CellBudgetFile(os.path.join(modelpth, "mp7p2.cbb")) spdis = cbb.get_data(text="SPDIS")[-1] @@ -1071,15 +1020,12 @@ def run_vertex_grid_example(ws): cb = plt.colorbar(patch_collection, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ## Plotting using built in styles # # FloPy's plotting routines can be used with built in styles from the `styles` module. The `styles` module takes advantage of matplotlib's temporary styling routines by reading in pre-built style sheets. Two different types of styles have been built for flopy: `USGSMap()` and `USGSPlot()` styles which can be used to create report quality figures. The styles module also contains a number of methods that can be used for adding axis labels, text, annotations, headings, removing tick lines, and updating the current font. # # This example will run the Keating groundwater transport model and plot results using `styles` -# + pycharm={"name": "#%%\n"} - example_name = "ex-gwt-keating" # Model units @@ -1351,10 +1297,8 @@ def run_keating_model(ws=example_name, silent=True): run_keating_model(modelpth) -# + [markdown] pycharm={"name": "#%% md\n"} # Load the flow and transport models -# + pycharm={"name": "#%%\n"} sim_path = os.path.join(modelpth, "mf6-gwt-keating", "mf6gwf") tr_path = os.path.join(modelpth, "mf6-gwt-keating", "mf6gwt") sim_name = "mfsim.nam" @@ -1368,7 +1312,6 @@ def run_keating_model(ws=example_name, silent=True): ) gwt6 = sim.get_model("trans") -# + pycharm={"name": "#%%\n"} # import styles from flopy.plot import styles @@ -1396,10 +1339,8 @@ def run_keating_model(ws=example_name, silent=True): styles.heading(letter="A.", heading="Simulated hydraulic head", fontsize=10) ax.set_aspect(1.0) -# + [markdown] pycharm={"name": "#%% md\n"} # Plotting concentration model results using the `USGSMap()` style -# + pycharm={"name": "#%%\n"} # load the transport output file cobj = gwt6.output.concentration() plot_times = [100, 1000, 3000] @@ -1439,14 +1380,12 @@ def run_keating_model(ws=example_name, silent=True): z = zgrid[k, i, j] ax.plot(x, z, mfc="yellow", mec="black", marker="o", ms="8") -# + [markdown] pycharm={"name": "#%% md\n"} # ## Summary # # This notebook demonstrates some of the plotting functionality available with flopy. Although not described here, the plotting functionality tries to be general by passing keyword arguments passed to the `PlotCrossSection` methods down into the `matplotlib.pyplot` routines that do the actual plotting. For those looking to customize these plots, it may be necessary to search for the available keywords by understanding the types of objects that are created by the `PlotCrossSection` methods. The `PlotCrossSection` methods return these matplotlib.collections objects so that they could be fine-tuned later in the script before plotting. # # Hope this gets you started! -# + pycharm={"name": "#%%\n"} try: # ignore PermissionError on Windows tempdir.cleanup() diff --git a/.docs/Notebooks/plot_map_view_example.py b/.docs/Notebooks/plot_map_view_example.py index ef3a3e8dc6..d58a3c39cf 100644 --- a/.docs/Notebooks/plot_map_view_example.py +++ b/.docs/Notebooks/plot_map_view_example.py @@ -17,7 +17,6 @@ # - name: Christian Langevin # --- -# + [markdown] pycharm={"name": "#%% md\n"} # # Making Maps of Your Model # This notebook demonstrates the mapping capabilities of FloPy. It demonstrates these capabilities by loading and running existing models and then showing how the PlotMapView object and its methods can be used to make nice plots of the model grid, boundary conditions, model results, shape files, etc. # @@ -47,7 +46,6 @@ print(f"matplotlib version: {mpl.__version__}") print(f"flopy version: {flopy.__version__}") -# + pycharm={"name": "#%%\n"} # Set name of MODFLOW exe # assumes executable is in users path statement v2005 = "mf2005" @@ -58,7 +56,7 @@ sim_name = "freyberg" # Set the paths -tempdir = TemporaryDirectory() +tempdir = TemporaryDirectory(delete=False) modelpth = Path(tempdir.name) # Check if we are in the repository and define the data path. @@ -70,7 +68,6 @@ data_path = root / "examples" / "data" if root else Path.cwd() -# + [markdown] pycharm={"name": "#%% md\n"} # ### Load and Run an Existing MODFLOW-2005 Model # A model called the "Freyberg Model" is located in the modelpth folder. In the following code block, we load that model, then change into a new workspace (modelpth) where we recreate and run the model. For this to work properly, the MODFLOW-2005 executable (mf2005) must be in the path. We verify that it worked correctly by checking for the presence of freyberg.hds and freyberg.cbc. @@ -113,7 +110,6 @@ errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Create and Run MODPATH 6 model # # The MODFLOW-2005 model created in the previous code block will be used to create a endpoint capture zone and pathline analysis for the pumping wells in the model. @@ -150,11 +146,9 @@ mpp.write_input() mpp.run_model() -# + [markdown] pycharm={"name": "#%% md\n"} # ### Creating a Map of the Model Grid # Now that we have a model, we can use the flopy plotting utilities to make maps. We will start by making a map of the model grid using the `PlotMapView` class and the `plot_grid()` method of that class. -# + pycharm={"name": "#%%\n"} # First step is to set up the plot fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") @@ -169,14 +163,12 @@ t = ax.set_title("Model Grid") -# + [markdown] pycharm={"name": "#%% md\n"} # ## Grid transformations and setting coordinate information # # The `PlotMapView` class can plot the position of the model grid in space. However, transformations must be done on the modelgrid using `set_coord_info()`. This allows the user to set the coordinate information once, and then they are able to generate as many instanstances of `PlotMapView` as they wish, without providing the coordinate info again. # # Here we demonstrate the effects of these values. In the first two plots, the grid origin (lower left corner) remains fixed at (0, 0). These first two plots demostrate how work with coordinate info in the `PlotMapView` class. The third example shows the grid origin set at (507000 E, 2927000 N) -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(18, 6)) ax = fig.add_subplot(1, 3, 1, aspect="equal") @@ -205,12 +197,10 @@ linecollection = mapview.plot_grid() t = ax.set_title("xoffset, yoffset, and rotation") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Ploting Ibound # # The `plot_ibound()` method can be used to plot the boundary conditions contained in the ibound arrray, which is part of the MODFLOW Basic Package. The `plot_ibound()` method returns a matplotlib QuadMesh object (matplotlib.collections.QuadMesh). If you are familiar with the matplotlib collections, then this may be important to you, but if not, then don't worry about the return objects of these plotting function. -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") @@ -220,17 +210,14 @@ quadmesh = mapview.plot_ibound() linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # We can also change the colors by calling the `color_noflow` and `color_ch` parameters in `plot_ibound()` and the `colors` parameter in `plot_grid()` -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") mapview = flopy.plot.PlotMapView(model=ml) quadmesh = mapview.plot_ibound(color_noflow="red", color_ch="orange") linecollection = mapview.plot_grid(colors="yellow") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Boundary Conditions # The plot_bc() method can be used to plot boundary conditions. It is setup to use the following dictionary to assign colors, however, these colors can be changed in the method call. # @@ -239,7 +226,6 @@ # # Here, we plot the location of river cells and the location of well cells. -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") mapview = flopy.plot.PlotMapView(model=ml) @@ -248,10 +234,8 @@ quadmesh = mapview.plot_bc("WEL") linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # The colors can be changed by using the `color_noflow` and `color_ch` parameters in `plot_ibound()`, the `color` parameter in `plot_bc()`, and the `colors` parameter in `plot_grid()` -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") mapview = flopy.plot.PlotMapView(model=ml) @@ -260,12 +244,10 @@ quadmesh = mapview.plot_bc("WEL", color="navy") linecollection = mapview.plot_grid(colors="yellow") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting an Array # # `PlotMapView` has a `plot_array()` method. The `plot_array()` method will accept either a 2D or 3D array. If a 3D array is passed, then the `layer` parameter for the `PlotMapView` object will be used (note that the `PlotMapView` object can be created with a `layer=` argument). -# + pycharm={"name": "#%%\n"} # Create a random array and plot it a = np.random.random((ml.dis.nrow, ml.dis.ncol)) @@ -277,7 +259,6 @@ linecollection = mapview.plot_grid() cb = plt.colorbar(quadmesh, shrink=0.5) -# + pycharm={"name": "#%%\n"} # Plot the model bottom array a = ml.dis.botm.array @@ -289,12 +270,10 @@ linecollection = mapview.plot_grid() cb = plt.colorbar(quadmesh, shrink=0.5) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Contouring an Array # # `PlotMapView` also has a `contour_array()` method. It also takes a 2D or 3D array and will contour the layer slice if 3D. -# + pycharm={"name": "#%%\n"} # Contour the model bottom array a = ml.dis.botm.array @@ -307,7 +286,6 @@ plt.colorbar(contour_set, shrink=0.75) -# + pycharm={"name": "#%%\n"} # The contour_array() method will take any keywords # that can be used by the matplotlib.pyplot.contour # function. So we can pass in levels, for example. @@ -329,10 +307,8 @@ sm.set_array([]) fig.colorbar(sm, shrink=0.75, ax=ax) -# + [markdown] pycharm={"name": "#%% md\n"} # Array contours can be exported directly to a shapefile. -# + pycharm={"name": "#%%\n"} from flopy.export.utils import ( # use export_contourf for filled contours export_contours, ) @@ -346,12 +322,10 @@ nshapes = len(r.shapes()) print("Contours:", nshapes) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Heads # # So this means that we can easily plot results from the simulation by extracting heads using `flopy.utils.HeadFile`. Here we plot the simulated heads. -# + pycharm={"name": "#%%\n"} fname = os.path.join(modelpth, "freyberg.hds") hdobj = flopy.utils.HeadFile(fname) head = hdobj.get_data() @@ -375,14 +349,12 @@ contour_set = mapview.contour_array(head, levels=levels) linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Discharge Vectors # # `PlotMapView` has a `plot_vector()` method, which takes vector components in the x- and y-directions at the cell centers. The x- and y-vector components are calculated from the `'FLOW RIGHT FACE'` and `'FLOW FRONT FACE'` arrays, which can be written by MODFLOW to the cell by cell budget file. These array can be extracted from the cell by cell flow file using the `flopy.utils.CellBudgetFile` object as shown below. Once they are extracted, they can be passed to the `postprocessing.get_specific_discharge()` method to get the discharge vectors and plotted using the `plot_vector()` method. # # **Note**: `postprocessing.get_specific_discharge()` also takes the head array as an optional argument. The head array is used to convert the volumetric discharge in dimensions of $L^3/T$ to specific discharge in dimensions of $L/T$. -# + pycharm={"name": "#%%\n"} fname = os.path.join(modelpth, "freyberg.cbc") cbb = flopy.utils.CellBudgetFile(fname) head = hdobj.get_data() @@ -415,12 +387,10 @@ quiver = mapview.plot_vector(sqx, sqy) # include the head array for specific discharge linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting MODPATH endpoints and pathlines # # `PlotMapView` has a `plot_endpoint()` and `plot_pathline()` method, which takes MODPATH endpoint and pathline data and plots them on the map object. Here we load the endpoint and pathline data and plot them on the head and discharge data previously plotted. Pathlines are shown for all times less than or equal to 200 years. Recharge capture zone data for all of the pumping wells are plotted as circle markers colored by travel time. -# + pycharm={"name": "#%%\n"} # load the endpoint data endfile = os.path.join(modelpth, mp.sim.endpoint_file) endobj = flopy.utils.EndpointFile(endfile) @@ -457,7 +427,6 @@ # plot the pathlines mapview.plot_pathline(plines, layer="all", colors="red", travel_time=ctt) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting a Shapefile # # `PlotMapView` has a `plot_shapefile()` method that can be used to quickly plot a shapefile on your map. In order to use the `plot_shapefile()` method, you must be able to "import shapefile". The command `import shapefile` is part of the pyshp package. @@ -519,20 +488,24 @@ ) copytree(data_path / sim_name / "gis", modelpth / "gis") +assert (modelpth / "gis").is_dir() -# + pycharm={"name": "#%%\n"} # Setup the figure and PlotMapView. Show a very faint map of ibound and # model grid by specifying a transparency alpha value. fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(1, 1, 1, aspect="equal") +assert (modelpth / "gis").is_dir() + # reset the grid rotation and offsets to 0 ml.modelgrid.set_coord_info(xoff=0, yoff=0, angrot=0) mapview = flopy.plot.PlotMapView(model=ml, ax=ax) # Plot a shapefile of +assert (modelpth / "gis").is_dir() shp = os.path.join(modelpth, "gis", "bedrock_outcrop_hole") +print(os.listdir(modelpth / "gis")) patch_collection = mapview.plot_shapefile( shp, edgecolor="green", @@ -554,10 +527,8 @@ quadmesh = mapview.plot_bc("RIV", alpha=0.1) linecollection = mapview.plot_grid(alpha=0.1) -# + [markdown] pycharm={"name": "#%% md\n"} # Although the `PlotMapView`'s `plot_shapefile()` method does not consider projection information when plotting maps, it can be used to plot shapefiles when a `PlotMapView` instance is rotated and offset into geographic coordinates. The same shapefiles plotted above (but in geographic coordinates rather than model coordinates) are plotted on the rotated model grid. The offset from model coordinates to geographic coordinates relative to the lower left corner are `xoff=-2419.22`, `yoff=297.04` and the rotation angle is 14$^{\circ}$. -# + pycharm={"name": "#%%\n"} # Setup the figure and PlotMapView. Show a very faint map of ibound and # model grid by specifying a transparency alpha value. @@ -590,7 +561,6 @@ quadmesh = mapview.plot_ibound(alpha=0.1) linecollection = mapview.plot_grid(alpha=0.1) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting GIS Shapes # # `PlotMapView` has a `plot_shapes()` method that can be used to quickly plot GIS based shapes on your map. In order to use the `plot_shapes()` method, you must be able to "import shapefile". The command import shapefile is part of the pyshp package. @@ -613,7 +583,6 @@ # # Here is a basic example of how to use the method: -# + pycharm={"name": "#%%\n"} # lets extract some shapes from our shapefiles shp = os.path.join(modelpth, "gis", "bedrock_outcrop_hole_rotate14") with shapefile.Reader(shp) as r: @@ -628,10 +597,8 @@ with shapefile.Reader(shp) as r: wells = r.shapes() -# + [markdown] pycharm={"name": "#%% md\n"} # Now that the shapes are extracted from the shapefiles, they can be plotted using `plot_shapes()` -# + pycharm={"name": "#%%\n"} # set the modelgrid rotation and offset ml.modelgrid.set_coord_info( xoff=-2419.2189559966773, yoff=297.0427372400354, angrot=-14 @@ -656,12 +623,10 @@ # plot_point(s) patch_collection3 = mapview.plot_shapes(wells, radius=100, facecolor="k", edgecolor="k") -# + [markdown] pycharm={"name": "#%% md\n"} # ## Working with MODFLOW-6 models # # `PlotMapView` has support for MODFLOW-6 models and operates in the same fashion for Structured Grids, Vertex Grids, and Unstructured Grids. Here is a short example on how to plot with MODFLOW-6 structured grids using a version of the Freyberg model created for MODFLOW-6 -# + pycharm={"name": "#%%\n"} # load the Freyberg model into mf6-flopy and run the simulation sim_name = "mf6-freyberg" @@ -716,12 +681,10 @@ errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting boundary conditions and arrays # # This works the same as modflow-2005, however the simulation object can host a number of modflow-6 models so we need to grab a model before attempting to plot with `PlotMapView` -# + pycharm={"name": "#%%\n"} # get the modflow-6 model we want to plot ml6 = sim.get_model("freyberg") ml6.modelgrid.set_coord_info(angrot=-14) @@ -748,12 +711,10 @@ linecollection = mapview.plot_grid() cb = plt.colorbar(quadmesh, shrink=0.5, ax=ax) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Contouring Arrays # # Contouring arrays follows the same code signature for MODFLOW-6 as the MODFLOW-2005 example. Just use the `contour_array()` method -# + pycharm={"name": "#%%\n"} # The contour_array() method will take any keywords # that can be used by the matplotlib.pyplot.contour # function. So we can pass in levels, for example. @@ -775,12 +736,10 @@ sm.set_array([]) fig.colorbar(sm, shrink=0.75, ax=ax) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting specific discharge with a MODFLOW-6 model # # MODFLOW-6 includes a the PLOT_SPECIFIC_DISCHARGE flag in the NPF package to calculate and store discharge vectors for easy plotting. The postprocessing module will translate the specific dischage into vector array and `PlotMapView` has the `plot_vector()` method to use this data. The specific discharge array is stored in the cell budget file. -# + pycharm={"name": "#%%\n"} # get the specific discharge from the cell budget file cbc_file = os.path.join(sim_path, "freyberg.cbc") cbc = flopy.utils.CellBudgetFile(cbc_file) @@ -805,12 +764,10 @@ plt.title("Specific Discharge (" + r"$L/T$" + ")") plt.colorbar(quadmesh, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # ## Vertex model plotting with MODFLOW-6 # # FloPy fully supports vertex discretization (DISV) plotting through the `PlotMapView` class. The method calls are identical to the ones presented previously for Structured discretization (DIS) and the same matplotlib keyword arguments are supported. Let's run through an example using a vertex model grid. -# + pycharm={"name": "#%%\n"} # build and run vertex model grid demo problem @@ -1115,7 +1072,6 @@ def run_vertex_grid_example(ws): errmsg = f"Error. Output file cannot be found: {f}" print(errmsg) -# + pycharm={"name": "#%%\n"} # load the simulation and get the model vertex_sim_name = "mfsim.nam" vertex_sim = flopy.mf6.MFSimulation.load( @@ -1126,14 +1082,12 @@ def run_vertex_grid_example(ws): ) vertex_ml6 = vertex_sim.get_model("mp7p2") -# + [markdown] pycharm={"name": "#%% md\n"} # ### Setting MODFLOW-6 Vertex Model Grid offsets, rotation and plotting # # Setting the `Grid` offsets and rotation is consistent in FloPy, no matter which type of discretization the user is using. The `set_coord_info()` method on the `modelgrid` is used. # # Plotting works consistently too, the user just calls the `PlotMapView` class and it accounts for the discretization type -# + pycharm={"name": "#%%\n"} # set coordinate information on the modelgrid vertex_ml6.modelgrid.set_coord_info(xoff=362100, yoff=4718900, angrot=-21) @@ -1145,7 +1099,6 @@ def run_vertex_grid_example(ws): mapview = flopy.plot.PlotMapView(vertex_ml6, layer=0) linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting boundary conditions with Vertex Model grids # # The `plot_bc()` method can be used to plot boundary conditions. It is setup to use the following dictionary to assign colors, however, these colors can be changed in the method call. @@ -1155,7 +1108,6 @@ def run_vertex_grid_example(ws): # # Here we plot river (RIV) cell locations -# + pycharm={"name": "#%%\n"} fig = plt.figure(figsize=(12, 12)) ax = fig.add_subplot(1, 1, 1, aspect="equal") ax.set_title("Vertex Model Grid (DISV)") @@ -1165,12 +1117,10 @@ def run_vertex_grid_example(ws): riv = mapview.plot_bc("RIV") linecollection = mapview.plot_grid() -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting Arrays and Contouring with Vertex Model grids # # `PlotMapView` allows the user to plot arrays and contour with DISV based discretization. The `plot_array()` method is called in the same way as using a structured grid. The only difference is that `PlotMapView` builds a matplotlib patch collection for Vertex based grids. -# + pycharm={"name": "#%%\n"} # get the head output for stress period 1 from the modflow6 head file head = flopy.utils.HeadFile(os.path.join(mp7modelpth, "mp7p2.hds")) hdata = head.get_alldata()[0, :, :, :] @@ -1184,10 +1134,8 @@ def run_vertex_grid_example(ws): linecollection = mapview.plot_grid(lw=0.25, color="k") cb = plt.colorbar(patch_collection, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # The `contour_array()` method operates in the same way as the sturctured example. -# + pycharm={"name": "#%%\n"} # plotting head array and then contouring the array! levels = np.arange(327, 332, 0.5) @@ -1205,12 +1153,10 @@ def run_vertex_grid_example(ws): cb = plt.colorbar(pc, shrink=0.75, ax=ax) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting MODPATH 7 results on a vertex model # # MODPATH-7 results can be plotted using the same built in methods as used previously to plot MODPATH-6 results. The `plot_pathline()` and `plot_timeseries()` methods are layered on the previous example to show modpath simulation results -# + pycharm={"name": "#%%\n"} # load the MODPATH-7 results mp_namea = "mp7p2a_mp" fpth = os.path.join(mp7modelpth, f"{mp_namea}.mppth") @@ -1221,7 +1167,6 @@ def run_vertex_grid_example(ws): ts = flopy.utils.TimeseriesFile(fpth) ts0 = ts.get_alldata() -# + pycharm={"name": "#%%\n"} # setup the plot fig = plt.figure(figsize=(12, 12)) ax = fig.add_subplot(1, 1, 1, aspect="equal") @@ -1242,11 +1187,9 @@ def run_vertex_grid_example(ws): for k in range(3): tseries = mapview.plot_timeseries(ts0, layer=k, marker="o", lw=0, color=colors[k]) -# + [markdown] pycharm={"name": "#%% md\n"} # ### Plotting specific discharge vectors for DISV # MODFLOW-6 includes a the PLOT_SPECIFIC_DISCHARGE flag in the NPF package to calculate and store discharge vectors for easy plotting. The postprocessing module will translate the specific dischage into vector array and `PlotMapView` has the `plot_vector()` method to use this data. The specific discharge array is stored in the cell budget file. -# + pycharm={"name": "#%%\n"} cbb = flopy.utils.CellBudgetFile( os.path.join(mp7modelpth, "mp7p2.cbb"), precision="double" ) @@ -1265,12 +1208,10 @@ def run_vertex_grid_example(ws): # plot specific discharge quiver = mapview.plot_vector(qx, qy, normalize=True, alpha=0.60) -# + [markdown] pycharm={"name": "#%% md\n"} # ## Unstructured grid (DISU) plotting with MODFLOW-USG and MODFLOW-6 # # Unstructured grid (DISU) plotting has support through the `PlotMapView` class and the `UnstructuredGrid` discretization object. The method calls are identical to those used for vertex (DISV) and structured (DIS) model grids. Let's run through a few unstructured grid examples -# + pycharm={"name": "#%%\n"} # set up the notebook for unstructured grid plotting from flopy.discretization import UnstructuredGrid @@ -1314,7 +1255,6 @@ def load_iverts(fname): return iverts, np.array(xc), np.array(yc) -# + pycharm={"name": "#%%\n"} # load vertices fname = os.path.join(datapth, "ugrid_verts.dat") verts = load_verts(fname) @@ -1323,10 +1263,8 @@ def load_iverts(fname): fname = os.path.join(datapth, "ugrid_iverts.dat") iverts, xc, yc = load_iverts(fname) -# + [markdown] pycharm={"name": "#%% md\n"} # In this case, verts is just a 2-dimensional list of x,y vertex pairs. iverts is also a 2-dimensional list, where the outer list is of size ncells, and the inner list is a list of the vertex numbers that comprise the cell. -# + pycharm={"name": "#%%\n"} # Print the first 5 entries in verts and iverts for ivert, v in enumerate(verts[:5]): print(f"Vertex coordinate pair for vertex {ivert}: {v}") @@ -1335,25 +1273,20 @@ def load_iverts(fname): for icell, vertlist in enumerate(iverts[:5]): print(f"List of vertices for cell {icell}: {vertlist}") -# + [markdown] pycharm={"name": "#%% md\n"} # A flopy `UnstructuredGrid` object can now be created using the vertices and incidence list. The `UnstructuredGrid` object is a key part of the plotting capabilities in flopy. In addition to the vertex information, the `UnstructuredGrid` object also needs to know how many cells are in each layer. This is specified in the ncpl variable, which is a list of cells per layer. -# + pycharm={"name": "#%%\n"} ncpl = np.array(5 * [len(iverts)]) umg = UnstructuredGrid(verts, iverts, xc, yc, ncpl=ncpl, angrot=10) print(ncpl) print(umg) -# + [markdown] pycharm={"name": "#%% md\n"} # Now that we have an `UnstructuredGrid`, we can use the flopy `PlotMapView` object to create different types of plots, just like we do for structured grids. -# + pycharm={"name": "#%%\n"} f = plt.figure(figsize=(10, 10)) mapview = flopy.plot.PlotMapView(modelgrid=umg) mapview.plot_grid() plt.plot(umg.xcellcenters, umg.ycellcenters, "bo") -# + pycharm={"name": "#%%\n"} # Create a random array for layer 0, and then plot it with a color flood and contours f = plt.figure(figsize=(10, 10)) @@ -1367,10 +1300,8 @@ def load_iverts(fname): linecollection = mapview.plot_grid(color="k", lw=0.5) colorbar = plt.colorbar(pc, shrink=0.75) -# + [markdown] pycharm={"name": "#%% md\n"} # Here are some examples of some other types of grids. The data files for these grids are located in the datapth folder. -# + pycharm={"name": "#%%\n"} from pathlib import Path fig = plt.figure(figsize=(10, 30)) @@ -1384,16 +1315,13 @@ def load_iverts(fname): linecollection = mapview.plot_grid(colors="sienna") ax.set_title(Path(fname).name) -# + [markdown] pycharm={"name": "#%% md\n"} # ## Plotting using built in styles # # FloPy's plotting routines can be used with built in styles from the `styles` module. The `styles` module takes advantage of matplotlib's temporary styling routines by reading in pre-built style sheets. Two different types of styles have been built for flopy: `USGSMap()` and `USGSPlot()` styles which can be used to create report quality figures. The styles module also contains a number of methods that can be used for adding axis labels, text, annotations, headings, removing tick lines, and updating the current font. -# + pycharm={"name": "#%%\n"} # import flopy's styles from flopy.plot import styles -# + pycharm={"name": "#%%\n"} # get the specific discharge from the cell budget file cbc_file = os.path.join(sim_path, "freyberg.cbc") cbc = flopy.utils.CellBudgetFile(cbc_file) @@ -1422,10 +1350,8 @@ def load_iverts(fname): styles.xlabel(label="Easting") styles.ylabel(label="Northing") -# + [markdown] pycharm={"name": "#%% md\n"} # Here is a second example showing how to change the font type using `styles` -# + pycharm={"name": "#%%\n"} # use USGSMap style, change font type, and plot without tick lines: with styles.USGSMap(): fig = plt.figure(figsize=(12, 12)) @@ -1450,17 +1376,16 @@ def load_iverts(fname): styles.ylabel(label="Northing", fontsize=12) styles.remove_edge_ticks() -# + [markdown] pycharm={"name": "#%% md\n"} # ## Summary # # This notebook demonstrates some of the plotting functionality available with FloPy. Although not described here, the plotting functionality tries to be general by passing keyword arguments passed to `PlotMapView` methods down into the `matplotlib.pyplot` routines that do the actual plotting. For those looking to customize these plots, it may be necessary to search for the available keywords by understanding the types of objects that are created by the `PlotMapView` methods. The `PlotMapView` methods return these `matplotlib.collections` objects so that they could be fine-tuned later in the script before plotting. # # Hope this gets you started! -# + pycharm={"name": "#%%\n"} try: # ignore PermissionError on Windows - tempdir.cleanup() + pass + # tempdir.cleanup() except: pass # - diff --git a/.docs/Notebooks/seawat_henry_example.py b/.docs/Notebooks/seawat_henry_example.py index 3d4de1b0ec..aebe7af447 100644 --- a/.docs/Notebooks/seawat_henry_example.py +++ b/.docs/Notebooks/seawat_henry_example.py @@ -31,7 +31,6 @@ print(f"numpy version: {np.__version__}") print(f"flopy version: {flopy.__version__}") -# + pycharm={"name": "#%%\n"} # temporary directory temp_dir = TemporaryDirectory() workspace = temp_dir.name diff --git a/.docs/Notebooks/shapefile_feature_examples.py b/.docs/Notebooks/shapefile_feature_examples.py index b745a24df0..84a9050cc6 100644 --- a/.docs/Notebooks/shapefile_feature_examples.py +++ b/.docs/Notebooks/shapefile_feature_examples.py @@ -114,7 +114,6 @@ recarray2shp(chk.summary_array, geoms, os.path.join(workspace, "test.shp"), crs=26715) shape_path = os.path.join(workspace, "test.prj") -# + pycharm={"name": "#%%\n"} shutil.copy(shape_path, os.path.join(workspace, "26715.prj")) recarray2shp( chk.summary_array, @@ -127,11 +126,9 @@ # ### read it back in # * flopy geometry objects representing the shapes are stored in the 'geometry' field -# + pycharm={"name": "#%%\n"} ra = shp2recarray(os.path.join(workspace, "test.shp")) ra -# + pycharm={"name": "#%%\n"} ra.geometry[0].plot() # - diff --git a/autotest/conftest.py b/autotest/conftest.py index 327f518292..9c44d46b6a 100644 --- a/autotest/conftest.py +++ b/autotest/conftest.py @@ -106,15 +106,6 @@ def pytest_addoption(parser): "check patch collections or figure & axis properties.)", ) - # for test_generate_classes.py - parser.addoption( - "--ref", - action="append", - type=str, - help="Include extra refs to test. Useful for testing branches on a fork, " - "e.g. /modflow6/.", - ) - def pytest_report_header(config): """Header for pytest to show versions of packages.""" diff --git a/autotest/test_notebooks.py b/autotest/test_notebooks.py index 4c853645dd..1c57ae7ad3 100644 --- a/autotest/test_notebooks.py +++ b/autotest/test_notebooks.py @@ -3,7 +3,7 @@ import pytest from flaky import flaky -from modflow_devtools.misc import run_cmd +from modflow_devtools.misc import is_in_ci, run_cmd from autotest.conftest import get_project_root_path @@ -31,10 +31,13 @@ def get_notebooks(pattern=None, exclude=None): + get_notebooks(pattern="example"), ) def test_notebooks(notebook): + in_ci = is_in_ci() args = ["jupytext", "--from", "py", "--to", "ipynb", "--execute", notebook] stdout, stderr, returncode = run_cmd(*args, verbose=True) - if returncode != 0: + # allow notebooks to fail for lack of optional dependencies in local runs, + # expect all dependencies to be present and notebooks to pass in ci tests. + if returncode != 0 and not in_ci: if "Missing optional dependency" in stderr: pkg = re.findall("Missing optional dependency '(.*)'", stderr)[0] pytest.skip(f"notebook requires optional dependency {pkg!r}") diff --git a/etc/environment.yml b/etc/environment.yml index 1128785219..7847197333 100644 --- a/etc/environment.yml +++ b/etc/environment.yml @@ -12,6 +12,7 @@ dependencies: # lint - cffconvert + - codespell>=2.2.2 - ruff # test @@ -23,29 +24,33 @@ dependencies: - jupytext - pip: - git+https://github.com/MODFLOW-USGS/modflow-devtools.git + - tach - pytest!=8.1.0 - pytest-benchmark - pytest-cov - pytest-dotenv - pytest-xdist + - pyzmq>=25.1.2, - syrupy - virtualenv # optional - affine - - scipy + - descartes + - fiona + - geojson + - geopandas + - GitPython + - imageio - netcdf4 + - pooch + - pymetis + - pyproj - pyshp + - pyvista - rasterio - - fiona - - descartes - - pyproj + - rasterstats + - scipy - shapely>=2.0 - - geos - - geojson - vtk - - rasterstats - - pyvista - - imageio - - pymetis - xmipy