Skip to content

plots.py overhaul#912

Closed
lkstrp wants to merge 15 commits intoPyPSA:masterfrom
lkstrp:plots
Closed

plots.py overhaul#912
lkstrp wants to merge 15 commits intoPyPSA:masterfrom
lkstrp:plots

Conversation

@lkstrp
Copy link
Copy Markdown
Member

@lkstrp lkstrp commented Jun 4, 2024

Here is a general overhaul of the plots.py module:

  • plots.py
    • Modularise and generalise n.plot() with NetworkPlotter class
    • Add type hints and update docstrings
    • Return plot collections as dict instead of dynamic list
      • Could be changed completely. I don't know all use cases for this, but if it is just for the legend, it would be easier if this is an argument
    • Deprecated:
      • flow to line_flow, link_flow, transformer_flow. See issue below
      • bus_norm, line_norm, link_norm, transformer_norm to x_cmap_norm
      • color_geomap to geomap_colors
  • Issues
  • Other
    • requests library is not needed anymore
    • Changes in geo.py
      • Move geo functions from plot.py here
      • Add type checking and docstrings
    • Better deprecation
      • Add utils.py with changed kwargs deprecation decorator
      • Use DeprecationWarning instead of logger warnings

Todos:

  • Rewrite n.iplot() with new structure
  • Add animations
  • Add option to plot cluster shapes
  • Improve general plotting documentation
  • Docstrings and types
  • Add tests
  • Could continue cleaning and simplify/ generalise things

Discuss:

  • More API changes
    • I would also change geomap to disable_geomap and add a geomap_res argument, instead of mixing types
    • Maybe even drop geomap and include it into projection
  • branch components
    • For all branch components we have many duplicated arguments, this could be simplified
    • branch_components could be dropped and controlled via attribute arguments
  • This is mainly a clean and split up of all the things happened before in n.plot()
    • More simplification with generalized branch component Collections could be added in the background without API changes
    • Collection return
      • The collection return is not very intuitive
      • Right now I changed it to a dict, but we could also return a custom class here, that would also allow a lot of other functionality. But this would be another PR I guess

Let me know what you think @FabianHofmann @fneum

@lkstrp lkstrp marked this pull request as ready for review June 4, 2024 16:10
@lkstrp lkstrp marked this pull request as draft June 4, 2024 16:10
Copy link
Copy Markdown
Contributor

@FabianHofmann FabianHofmann left a comment

Choose a reason for hiding this comment

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

this is a very good direction! Just looked through it and I think we are on a good track. some minor comments below. I guess the plan is to use the NetworkPlotter (which we could also name NetworkMapPlotter if that is specifying its purpose) for n.iplot as well?

pypsa/utils.py Outdated
Comment on lines +41 to +73
def rename_kwargs(func_name: str, kwargs: dict[str, Any], aliases: dict[str, str]):
"""
Helper function for deprecating function arguments.

Based on solution from [here](https://stackoverflow.com/questions/49802412).

Parameters
----------
func_name : str
The name of the function.
kwargs : dict
The keyword arguments of the function.
aliases : dict
A mapping of old argument names to new argument names.

"""

for alias, new in aliases.items():
if alias in kwargs:
if new in kwargs:
raise TypeError(
f"{func_name} received both {alias} and {new} as arguments!"
f" {alias} is deprecated, use {new} instead."
)
warnings.warn(
message=(
f"`{alias}` is deprecated as an argument to `{func_name}`; use"
f" `{new}` instead."
),
category=DeprecationWarning,
stacklevel=3,
)
kwargs[new] = kwargs.pop(alias)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

that's cool!

self.ax = None # Initialized in init_axis
self.area_factor = 1 # Initialized in init_axis

def init_layout(self, layouter: nx.drawing.layout = None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

perhaps rather name it set_... instead of init_... to be close to the matplotlib naming

if not isinstance(projection, cartopy.crs.Projection):
self.boundaries = boundaries

def _add_geomap_features(self, geomap=True, geomap_colors=None):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would keep that as a non-hidden function, so that the use can add the geomap layer after initializing a plot

def init_axis(self, ax, projection, geomap, geomap_colors, title):
# Set up plot (either cartopy or matplotlib)

transform = get_projection_from_crs(self.n.srid)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rather use self.n.crs here

for branch in branches.values():
plotter.ax.add_collection(branch)

# Plot flows
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this still feels a bit weird that we are defining all branch components separately to then put them together into the get_branch_collections function where we iterate over them again. I would vote for making get_branch_collection process one branch component at a time

@fneum
Copy link
Copy Markdown
Member

fneum commented Jul 11, 2024

I would also change geomap to disable_geomap and add a geomap_res argument, instead of mixing types

Fine with renaming, but maybe in order to not swap meaning of True/False consider enable_geomap instead of disable_geomap.

  * Maybe even drop `geomap` and include it into `projection`

This should make sense. Geo-features are then automatically activated if projection is not None or hasattr(ax, "projection").

* branch components
  
  * For all branch components we have many duplicated arguments, this could be simplified

I think arguments for branch components should remain separately configurable. At some point we had an aggregated argument for all branch components where one had to supply a dictionary with keys for "Line", "Link", etc. or a pd.MultiIndex with the first level referring to the compontent. We preferred the flat format with duplication.

  * `branch_components` could be dropped and controlled via attribute arguments

Yes, should not be necessary, especially if no elements are created when link_widths=0 (skipped by width threshold).

* This is mainly a clean and split up of all the things happened before in `n.plot()`
  
  * More simplification with generalized branch component Collections could be added in the background without API changes
  * Collection return
    
    * The collection return is not very intuitive
    * Right now I changed it to a dict, but we could also return a custom class here, that would also allow a lot of other functionality. But this would be another PR I guess

Would not prioritize the collections. I think few people are accessing this afterwards, but dict seems to be a good idea.

@FabianHofmann FabianHofmann mentioned this pull request Jan 13, 2025
7 tasks
@lkstrp
Copy link
Copy Markdown
Member Author

lkstrp commented Mar 6, 2025

Closed via #1156

@lkstrp lkstrp closed this Mar 6, 2025
@lkstrp lkstrp mentioned this pull request Mar 6, 2025
21 tasks
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.

warning suppression for notebooks Plotting: split flow into line_flow, link_flow, transformer_flow to avoid multiindex

3 participants