Allow passing None explicitly to pygmt functions Part 1#1857
Conversation
Refactor grdimage to check `if "I" in kwargs` to using `if kwargs.get("I") is not None`.
Specifically when output_type="pandas" too.
Or rather, catch it properly if someone uses spec=None.
|
I think I'll stop here for now to keep this PR fairly 'small'. There's still a list of other functions that need to be refactored to use
Would someone else be willing to open a Part 2 PR for this? |
I could open part 2. |
Cool, I tried to use the walrus operator in this Part 1 PR but it didn't seem to work for the functions I was refactoring. Maybe you'll have better luck in Part 2 😉 |
Should I open the PR before or after this one is approved/merged? |
You can open the Part 2 PR now if you want, I think there shouldn't be any conflicts. Probably better to work on both in parallel too in case we notice anything wrong with the implementation in one or the other. |
Co-authored-by: Meghan Jones <meghanj@alum.mit.edu> Co-authored-by: Dongdong Tian <seisman.info@gmail.com>
|
/format |
|
Just to be safe, let's wait until the Part 2 PR is opened and finalized before merging this into the main branch. I'll keep this PR in draft for now. |
Working on it now! |
|
I am leaving meca out of part 2, since it is undergoing a complete refactor in #1784. |
| @@ -238,8 +238,12 @@ def velo(self, data=None, **kwargs): | |||
| """ | |||
| kwargs = self._preprocess(**kwargs) # pylint: disable=protected-access | |||
There was a problem hiding this comment.
This isn't really related to the PR, but it's something that I found confusing while working on part 2. Why is kwargs passed to figure._preprocess? It doesn't look like it is used at all.
There was a problem hiding this comment.
Good question, this ensures that velo is plotted to the right instance of the figure (e.g. if someone does fig1, fig2, etc). See also #1072 (comment). The _preprocess code is here:
Lines 109 to 115 in 0aa04d7
There was a problem hiding this comment.
It makes sense to me why we call the figure method to ensure the correct figure is activated in the session. I still don't really understand why we pass and return kwargs to/from _preprocess, or even why we call _preprocess at all rather than calling _activate_figure directly. I pushed a new branch to demonstrate the point of confusion, in which I replaced all the kwargs = self._preprocess(**kwargs) with self._activate_figure which seems more readable, a tiny bit faster, and still seems to work fine.
There was a problem hiding this comment.
This was setup for any other preprocessing of kwargs that may be needed or other figure plotting methods. At the time, I put this in place to allow things like passing pygmt.Figure(projection=pygmt.Mercator(), width="25c") and then inserting the projection code into the first plot command.
It could also be useful for any bookkeeping operation that is needed, like activating the figure, activating a subplot, etc.
pygmt/src/grdgradient.py
Outdated
| if kwargs.get("G") is None: # if outgrid is unset, output to tempfile | ||
| kwargs.update({"G": tmpfile.name}) | ||
| outgrid = kwargs["G"] |
There was a problem hiding this comment.
| if kwargs.get("G") is None: # if outgrid is unset, output to tempfile | |
| kwargs.update({"G": tmpfile.name}) | |
| outgrid = kwargs["G"] | |
| if (outgrid := kwargs.get("G")) is None: | |
| kwargs["G"] = outgrid = tmpfile.name # output to tmpfile |
I think this is slightly more readable (inspired by item number 16 in Effective Python (2021)).
There was a problem hiding this comment.
Ok, my brain is telling me that there's a reason not to do variable assignment like a = b = "c", something about how changing b would also change a but after some testing, it seems to be ok. Maybe I'm just thinking of some other programming language I've used before like Matlab, Javascript or Python 2 🤷
Co-authored-by: Meghan Jones <meghanj@alum.mit.edu>
|
Search for |
Oops, not sure how I missed all of that. Looks like we need a Part 3 😅 Do you want to open up that PR @seisman? |
OK, I'll open a PR later. |
…ngTools#1857) Implements a more robust check for None values in pygmt functions. * Let grdimage shading=None or False work Refactor grdimage to check `if "I" in kwargs` to using `if kwargs.get("I") is not None`. * Let grd2cpt's categorical, cyclic and output work with None input * Let grd2xyz's outcols work with None input Specifically when output_type="pandas" too. * Let grdgradient's tiles, normalize and outgrid work with None input * Let grdview's drapegrid work with None inputs * Let makecpt's categorical, cyclic and output work with None inputs * Let plot's style, color, intensity and transparency work with None input * Let plot3d's style, color, intensity & transparency work with None input * Let solar's T work with None input * Let transparency work with 0, None and False input * Let project's center, convention and generate work with None inputs * Let velo's spec work with None inputs Or rather, catch it properly if someone uses spec=None. * Update pygmt/src/grdgradient.py using walrus operator Co-authored-by: Meghan Jones <meghanj@alum.mit.edu> Co-authored-by: Dongdong Tian <seisman.info@gmail.com>
Description of proposed changes
Several PyGMT functions have
Noneas the default value (as seen in the docstring), but if a user were to explicitly set aNoneargument, this can fail. This Pull Request implements a more robust check forNonevalues, as discussed in #1665 (comment)For example, in the case of
grdimage, instead of checkingif "I" in kwargs, it is usually better to doif kwargs.get("I") is not None.TODO:
Fixes #1852, closes #1807
Reminders
make formatandmake checkto make sure the code follows the style guide.doc/api/index.rst.Slash Commands
You can write slash commands (
/command) in the first line of a comment to performspecific operations. Supported slash commands are:
/format: automatically format and lint the code/test-gmt-dev: run full tests on the latest GMT development version