Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@yunjunz
Copy link
Member

@yunjunz yunjunz commented Nov 12, 2025

Description of proposed changes

This PR adds view.py --shp-file/color/linewidth options to plot line/polygon from ESRI shapefiles or GMT lonlat file format.

  • utils.arg_utils.py: add add_shape_argument() to parse shape files from ESRI and GMT, including file path, color, linewidth, etc. The previous --faultline related options are still supported for backward compatibility.

  • utils.plot: add the following new functions:

    • add plot_shapefile() to read and plot ERSI shapefiles using gdal and plot using matplotlib
    • rename plot_faultline() to plot_gmt_lonlat_file()
    • add plot_shape() to call the above two functions.
  • plate_motion.py:

    • add Liu et al. (2025) to the reference
    • simplify the reference on the NNR-PMMs

Reminders

  • Pass Pre-commit check (green)
  • Pass Codacy code review (green)
  • Pass Circle CI test (green)
  • Make sure that your code follows our style. Use the other functions/files as a basis.
  • If modifying functionality, describe changes to function behavior and arguments in a comment below the function declaration.
  • If adding new functionality, add a detailed description to the documentation and/or an example.

Summary by Sourcery

Add support for plotting line and polygon shapes from ESRI shapefiles and GMT lonlat files via a new --shp-file interface in view, backed by new plot_shapefile and plot_shape functions, and unify related argument parsing; also update plate_motion references.

New Features:

  • Add --shp-file, --shp-color, --shp-lw, and --shp-min-dist arguments to the view CLI for plotting ESRI shapefiles and GMT lonlat files.

Enhancements:

  • Introduce plot_shape dispatcher to handle both ESRI shapefiles and GMT lonlat files and rename plot_faultline to plot_gmt_lonlat_file.
  • Implement plot_shapefile function using GDAL/OGR for reading and plotting ESRI shapefiles.
  • Refactor argument parsing by removing dedicated faultline flags and consolidating them under the new shape argument group with backward compatibility aliases.
  • Update view.py and cli/view.py to call the new generic shape plotting interface.

Documentation:

  • Update CLI examples in view commands to demonstrate the new --shp-file usage.

+ add Liu et al. (2025) to the reference
+ simplify the reference on the NNR-PMMs
…T lonlat files

+ utils.arg_utils.py: add `add_shape_argument()` to parse shape files from ESRI and GMT, including file path, color, linewidth, etc. The previous --faultline options are still supported for backward compatibility.

+ view:
   - add view.py --shp-file --shp-color --shp-linewidth options

+ utils.plot: add the following new functions:
   - add `plot_shapefile()` to read and plot ERSI shapefiles using gdal and plot using matplotlib
   - rename `plot_faultline()` to `plot_gmt_lonlat_file()`
   - add `plot_shape()` to call the above two functions.
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 12, 2025

Reviewer's Guide

This PR extends the view command to support plotting arbitrary line and polygon shapes from ESRI shapefiles and GMT lon-lat files by introducing new argument parsing and matplotlib routines, while preserving backward compatibility with existing faultline options.

Sequence diagram for plotting shapes from CLI to plotting routines

sequenceDiagram
    actor User
    participant CLI["view.py"]
    participant ArgParser["arg_utils.py"]
    participant Plot["utils.plot.py"]
    User->>CLI: Run view.py with --shp-file
    CLI->>ArgParser: Parse --shp-file, --shp-color, --shp-lw, --shp-min-dist
    ArgParser->>CLI: Return parsed arguments
    CLI->>Plot: Call plot_shape(ax, shp_files, ...)
    Plot->>Plot: For each shp_file, call plot_shapefile or plot_gmt_lonlat_file
    Plot->>CLI: Return updated plot
Loading

Class diagram for new and updated plotting functions in utils.plot

classDiagram
    class plot_shape {
        +plot_shape(ax, shp_files, SNWE, color, linewidth, min_dist, print_msg)
    }
    class plot_shapefile {
        +plot_shapefile(ax, shp_file, color, linewidth, print_msg)
    }
    class plot_gmt_lonlat_file {
        +plot_gmt_lonlat_file(ax, shp_file, SNWE, min_dist, color, linewidth, print_msg)
    }
    plot_shape --> plot_shapefile : calls
    plot_shape --> plot_gmt_lonlat_file : calls
Loading

Class diagram for argument parsing changes in arg_utils.py

classDiagram
    class add_shape_argument {
        +add_shape_argument(parser)
        --shp-file
        --shp-color
        --shp-lw
        --shp-min-dist
    }
    class add_map_argument {
        -removed: --faultline
        -removed: --faultline-lw
        -removed: --faultline-min-dist
    }
    add_shape_argument ..> add_map_argument : replaces faultline args
Loading

File-Level Changes

Change Details Files
Add unified shape argument parsing and deprecate legacy faultline flags
  • Introduce add_shape_argument() to define --shp-file, --shp-color, --shp-lw and --shp-min-dist options
  • Remove standalone --faultline, --faultline-lw and --faultline-min-dist from add_map_argument()
  • Ensure backward compatibility by mapping old faultline aliases to new shp-flags
src/mintpy/utils/arg_utils.py
Implement new plotting functions for ESRI and GMT shapes
  • Add plot_shapefile() using GDAL/OGR to read and transform shapefiles for plotting
  • Rename plot_faultline() to plot_gmt_lonlat_file() and expose color/linewidth parameters
  • Create plot_shape() wrapper to dispatch based on file extension and preserve axes limits
src/mintpy/utils/plot.py
Integrate shape plotting into view.py
  • Replace conditional plot_faultline() call with plot_shape() and pass shp_file list
  • Forward new color, linewidth and min-dist arguments from inps
  • Retain print_msg and SNWE handling
src/mintpy/view.py
Update CLI parser and examples to expose shape options
  • Add add_shape_argument() invocation to CLI parser for view commands
  • Update help text, examples and conflict checking to reference --shp-file instead of --faultline
  • Adjust geo_opt_names set to include shp-file
src/mintpy/cli/view.py
Refresh plate_motion references
  • Insert Liu et al. (2025) citation
  • Condense formatting of existing NNR-PMM model references
src/mintpy/cli/plate_motion.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `src/mintpy/utils/plot.py:1536-1537` </location>
<code_context>
+        if shp_file.endswith('.shp'):
+            plot_shapefile(ax, shp_file, **kwargs)
+
+        elif shp_file.endswith('.lonlat'):
+            plot_gmt_lonlat_file(ax, shp_file, SNWE, min_dist=0.1, print_msg=print_msg, **kwargs)
+
+    # keep the same axis limit
</code_context>

<issue_to_address>
**issue (bug_risk):** Hardcoded min_dist value may override user input.

Currently, plot_gmt_lonlat_file always uses min_dist=0.1, which ignores any min_dist value provided to plot_shape. Please pass the min_dist argument through to preserve user input.
</issue_to_address>

### Comment 2
<location> `src/mintpy/utils/plot.py:1622` </location>
<code_context>
+            ax.plot(geom.GetX(), geom.GetY(), "o", **kwargs)
+
+        else:
+            warning.warn(f'Un-recognized geometry type: {geom_type}! Ignore and continue.')
+
+    return ax
</code_context>

<issue_to_address>
**issue (typo):** Potential typo: 'warning.warn' should be 'warnings.warn'.

Using 'warning.warn' instead of 'warnings.warn' will cause a NameError unless 'warning' is defined.
</issue_to_address>

### Comment 3
<location> `src/mintpy/utils/arg_utils.py:477-481` </location>
<code_context>
+    """Argument group parser to plot shapes (line, polygon) in ERSI shapefile or GMT lonlat format."""
+    shp = parser.add_argument_group('Shapes', 'Plot various shapes (line, polygon) in ERSI or GMT format.')
+    shp.add_argument('--shp-file','--faultline', dest='shp_file', type=str, nargs='*',
+                     help='Shape files in ERSI shapefile or GMT lonlat format.')
+    shp.add_argument('--shp-color', dest='shp_color', type=str, default='k',
+                     help='Shape color (default: %(default)s).')
</code_context>

<issue_to_address>
**nitpick (typo):** Typo in help string: 'ERSI' should be 'ESRI'.

The help string should use 'ESRI shapefile' instead of 'ERSI shapefile' for accuracy.

```suggestion
def add_shape_argument(parser):
    """Argument group parser to plot shapes (line, polygon) in ESRI shapefile or GMT lonlat format."""
    shp = parser.add_argument_group('Shapes', 'Plot various shapes (line, polygon) in ESRI or GMT format.')
    shp.add_argument('--shp-file','--faultline', dest='shp_file', type=str, nargs='*',
                     help='Shape files in ESRI shapefile or GMT lonlat format.')
```
</issue_to_address>

### Comment 4
<location> `src/mintpy/utils/arg_utils.py:484-486` </location>
<code_context>
+                     help='Shape color (default: %(default)s).')
+    shp.add_argument('--shp-lw','--shp-linewidth','--faultline-lw', dest='shp_linewidth',
+                     default=0.5, type=float, metavar='NUM',
+                     help='Shpae linewidth (default: %(default)s).')
+    shp.add_argument('--shp-min-dist','--faultline-min-dist', dest='shp_min_dist', type=float,
+                     default=0.1, metavar='NUM',
</code_context>

<issue_to_address>
**nitpick (typo):** Typo in help string: 'Shpae' should be 'Shape'.

```suggestion
    shp.add_argument('--shp-lw','--shp-linewidth','--faultline-lw', dest='shp_linewidth',
                     default=0.5, type=float, metavar='NUM',
                     help='Shape linewidth (default: %(default)s).')
```
</issue_to_address>

### Comment 5
<location> `src/mintpy/utils/plot.py:1547` </location>
<code_context>
+    return ax
+
+
+def plot_shapefile(ax, shp_file, color='k', linewidth=0.5, print_msg=True):
+    """Plot shapes (line or polygon) in ESRI shapefile format.
+
</code_context>

<issue_to_address>
**issue (complexity):** Consider refactoring plotting logic by introducing helper functions to unify and simplify geometry handling and plotting.

Here’s one way to collapse most of that nested/duplicated plotting logic by pulling out two small helpers:

```python
# new helper, anywhere near top‐level
def plot_sequences(ax, sequences, **kwargs):
    """Plot each (x,y) tuple in sequences on ax."""
    for x, y in sequences:
        ax.plot(x, y, **kwargs)
    return ax

# new helper for OGR geometries
def iter_geom_coords(geom):
    """Yield (x, y) lists for any Polygon/MultiPolygon/LineString/…"""
    t = geom.GetGeometryType()
    # single Polygon
    if t in (ogr.wkbPolygon, ogr.wkbPolygon25D):
        for ring in geom:
            pts = ring.GetPointCount()
            yield ([ring.GetX(i) for i in range(pts)],
                   [ring.GetY(i) for i in range(pts)])
    # multi‐polygon
    elif t in (ogr.wkbMultiPolygon, ogr.wkbMultiPolygon25D):
        for part in geom:
            yield from iter_geom_coords(part)
    # single LineString
    elif t in (ogr.wkbLineString, ogr.wkbLineString25D):
        pts = geom.GetPointCount()
        yield ([geom.GetX(i) for i in range(pts)],
               [geom.GetY(i) for i in range(pts)])
    # multi‐line
    elif t in (ogr.wkbMultiLineString, ogr.wkbMultiLineString25D):
        for part in geom:
            yield from iter_geom_coords(part)
    # point
    elif t == ogr.wkbPoint:
        yield [geom.GetX()], [geom.GetY()]

# refactored plot_shapefile
def plot_shapefile(ax, shp_file, color='k', linewidth=0.5, print_msg=True):
    from osgeo import ogr, osr
    # … open ds, layer, build transform exactly as before …
    kwargs = dict(color=color, linewidth=linewidth)
    for feature in layer:
        geom = feature.GetGeometryRef()
        if not source_srs.IsGeographic():
            if print_msg:
                print("▶ converting to lon/lat…")
            geom.Transform(transform)
        # single loop over all coord sequences
        ax = plot_sequences(ax, iter_geom_coords(geom), **kwargs)
    return ax

# simplified GMT lonlat plotting
def plot_gmt_lonlat_file(ax, shp_file, SNWE, min_dist=0.1, **kwargs):
    faults = readfile.read_gmt_lonlat_file(shp_file, SNWE=SNWE,
                                           min_dist=min_dist,
                                           print_msg=kwargs.pop('print_msg', True))
    if not faults:
        warnings.warn("…skip plotting")
        return ax, faults
    seqs = [(f[:,0], f[:,1]) for f in faults]
    return plot_sequences(ax, seqs, **kwargs), faults
```

This:

- removes the nested `draw_polygon`,
- collapses all `if geom_type …` blocks into one generator,
- unifies plotting of shapefiles + GMT files via `plot_sequences`,
- eliminates repeated `ax.plot(…, color, linewidth)` calls.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

yunjunz and others added 3 commits November 12, 2025 13:06
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@yunjunz yunjunz merged commit b656901 into insarlab:main Nov 12, 2025
8 checks passed
@yunjunz yunjunz deleted the plot_shp branch November 12, 2025 06:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant