Skip to content

DOC: clarify difference between G.nodes/G.nodes() and G.edges/G.edges() in tutorial#8300

Merged
dschult merged 15 commits intonetworkx:mainfrom
Aka2210:docs-clarify-nodes-edges-docstring
Dec 6, 2025
Merged

DOC: clarify difference between G.nodes/G.nodes() and G.edges/G.edges() in tutorial#8300
dschult merged 15 commits intonetworkx:mainfrom
Aka2210:docs-clarify-nodes-edges-docstring

Conversation

@Aka2210
Copy link
Copy Markdown
Contributor

@Aka2210 Aka2210 commented Sep 29, 2025

Added a note to the Graph class docstring explaining that:

  • G.nodes is a NodeView (set-like)
  • G.nodes() returns a NodeDataView (with optional data/default arguments)
  • G.edges is an EdgeView (set-like)
  • G.edges() returns an EdgeDataView (with optional nbunch/data/default arguments)

This helps new users distinguish between attribute views and their callable forms, as suggested in #8253.

Related to #8253

…() in Graph docstring

Added a note to the Graph class docstring explaining that:
- G.nodes is a NodeView (set-like)
- G.nodes() returns a NodeDataView (with optional data/default arguments)
- G.edges is an EdgeView (set-like)
- G.edges() returns an EdgeDataView (with optional nbunch/data/default arguments)

This helps new users distinguish between attribute views and their callable forms,
as suggested in networkx#8253.
@Aka2210
Copy link
Copy Markdown
Contributor Author

Aka2210 commented Sep 29, 2025

Apologies if this is a naive question, but I noticed that the ci/circleci: documentation job failed on my PR. I came across issue #8297 which mentions intermittent doc build failures (possibly related to the new iplotx example). Could you please confirm if this failure is related to my changes, or if it’s part of the ongoing issue? I just want to make sure I’m not overlooking something on my end.

@rossbar
Copy link
Copy Markdown
Contributor

rossbar commented Sep 29, 2025

There are indeed problems with NX's circleci setup at the moment. The root cause has not yet been chased down but for now it's safe to simply ignore the red-x's from circleci. Sorry for the inconvenience!

@Aka2210
Copy link
Copy Markdown
Contributor Author

Aka2210 commented Sep 29, 2025

Got it — thanks a lot for clarifying!

Copy link
Copy Markdown
Contributor

@rossbar rossbar left a comment

Choose a reason for hiding this comment

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

Thanks for the proposal @Aka2210 !

I think this is on the right track but there's additional information + other perspectives that I think should be emphasized.

IMO one of the most important aspects is that the .nodes/.edges properties can be used to set node and edge attributes respectively. In principle, both *View and *DataView classes support attribute assignment, but in practice the convention (at least for me) is to use .nodes/.edges with attribute-like (i.e. no parentheses) access patterns for setting individual node/edge attributes, and .nodes()/.edges()` (i.e. property-like access patterns) for reporting. In other words --- attribute-like for setting, property/method-like for getting. Additionally, IMO the exact type of the return object (i.e. *View or *DataView) is very often an implementation detail that doesn't carry a whole lot of concrete meaning for typical users (aside from pointing them towards which docs to continue reading for more info). I'd prefer to de-emphasize the type of the returned objects and instead highlight conventional/recommended access patterns.

Related to the above - there is one key (ha!) difference in how multigraphs behave with .edges vs. edges() --- the former includes the key by default whereas the latter doesn't. This too agrees with the "attr-for-setting, "property-for-getting" pattern that I personally think is the bit most worth emphasizing. This also means that the Graph docstring is probably not the right place for this to live - I'd vote somewhere more central/general such as the introduction or tutorial.

@Aka2210
Copy link
Copy Markdown
Contributor Author

Aka2210 commented Oct 6, 2025

Got it — thanks for the clarification!
I’ll update the docstring accordingly: de-emphasize the detailed explanation of the *View / *DataView types, and instead highlight the common usage convention (using .nodes / .edges for setting attributes and .nodes() / .edges() for querying).

… in tutorial

This adds a new subsection to the tutorial explaining the distinction between
attribute-like (`G.nodes`, `G.edges`) and method-like (`G.nodes()`, `G.edges()`)
graph views.

It also adds a concise note and example for multigraphs(`MultiGraph`, `MultiDiGraph`)
@Aka2210
Copy link
Copy Markdown
Contributor Author

Aka2210 commented Oct 8, 2025

I’ve made the suggested changes — de-emphasized the *View / *DataView type details,
emphasized the “attribute-like for setting, method-like for getting” convention,
and added a short multigraph note showing the key-handling difference.

I also placed the new subsection right after “Examining elements of a graph”,
since that’s the first place in the tutorial where both attribute and method forms appear in examples.
I thought it’d be a natural spot to explain the distinction,
but I’m happy to move it if you feel it belongs elsewhere.

@Aka2210 Aka2210 changed the title DOC: clarify difference between G.nodes/G.nodes() and G.edges/G.edges() in Graph docstring DOC: clarify difference between G.nodes/G.nodes() and G.edges/G.edges() in tutorial Oct 8, 2025
doc/tutorial.md Outdated
list(G.nodes), list(G.nodes()), list(G.edges), list(G.edges())
```

Although they behave identically, each form is typically used differently in practice.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But G.edges does not behave identically to G.edges().
When iterated over, G.edges yields 3-tuples (u, v, edge_key) for multigraphs and 2-tuples (u, v) for graphs.
G.edges() yields 2-tuples for each edge for all graph objects. So, if you want to write code that will work for all graph objects, G.edges() helps avoide checking for multigraphs when you will ignore the edge key anyway.

But this is probably way too much for a tutorial. Can we qualify the "identically" somehow to make it accurate?
Maybe basically the same, or identically for Graphs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing that out!
I’ve revised the sentence to “Although they behave identically for the simple graphs…” to clarify that the statement only applies to Graph/DiGraph, not to MultiGraph objects.

@Aka2210
Copy link
Copy Markdown
Contributor Author

Aka2210 commented Oct 15, 2025

I merged the MultiGraph initialization and the first list(MG.edges) call into a single code cell to avoid the stray output (1) that appeared in the rendered tutorial.

Before:

MG = nx.MultiGraph()
MG.add_edge(1, 2)   # key=0
MG.add_edge(1, 2)   # key=1
1

(Rendered output included an unintended 1 because add_edge returns the edge key.)

After:

MG = nx.MultiGraph()
MG.add_edge(1, 2)   # key=0
MG.add_edge(1, 2)   # key=1
list(MG.edges)
[(1, 2, 0), (1, 2, 1)]

Combining them in one cell ensures that the last executed expression is the intended example output (list(MG.edges)) rather than the return value of add_edge.
This keeps the rendered tutorial clean.

Copy link
Copy Markdown
Contributor

@rossbar rossbar left a comment

Choose a reason for hiding this comment

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

Thanks for the updates @Aka2210 - after reading through this and the previous discussion, the impression I was left with was this was a lot of nitty-gritty detail for the tutorial.

I've left a concrete suggestion in the inline review comments that IMO at least is a slightly higher-level look that flows with the tutorial. Now, it doesn't cover everything - in fact the lack of any explicit mention of views is intentional - but I think it may fit with the tutorial better, while some of the finer-grained detail could be added later/elsewhere, e.g. the documentation on view objects. WDYT?

@Aka2210
Copy link
Copy Markdown
Contributor Author

Aka2210 commented Dec 5, 2025

Thanks for the updates @Aka2210 - after reading through this and the previous discussion, the impression I was left with was this was a lot of nitty-gritty detail for the tutorial.

I've left a concrete suggestion in the inline review comments that IMO at least is a slightly higher-level look that flows with the tutorial. Now, it doesn't cover everything - in fact the lack of any explicit mention of views is intentional - but I think it may fit with the tutorial better, while some of the finer-grained detail could be added later/elsewhere, e.g. the documentation on view objects. WDYT?

Thanks again for the detailed explanation and suggested wording!

I’ve updated the tutorial section to match your “Access patterns” version and verified that the (attributes) link correctly points to the “Adding attributes to graphs, nodes, and edges” section in the tutorial.

I've also fixed the style issues noted in CI.
I agree that keeping the tutorial high-level and leaving out explicit discussion of views here makes sense.
Thanks for the guidance!

Copy link
Copy Markdown
Contributor

@rossbar rossbar left a comment

Choose a reason for hiding this comment

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

Thanks @Aka2210 - this is a tricky thing to document so thanks for the iterations!

Copy link
Copy Markdown
Member

@dschult dschult left a comment

Choose a reason for hiding this comment

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

This looks good to me!
Thanks @Aka2210 and @rossbar

@dschult dschult merged commit 96b6282 into networkx:main Dec 6, 2025
52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants