@@ -218,7 +218,9 @@ def draw(
218218 If those are single values, `interpolate_sizes` is ignored
219219 for it. By default, True.
220220 **kwargs : optional args
221- Alternate default values. Values that can be overwritten are the following:
221+ Accepts three non-overlapping groups of keyword arguments:
222+
223+ Size-rescaling settings (see also ``rescale_sizes``):
222224
223225 * "min_node_size" (default: 5)
224226 * "max_node_size" (default: 30)
@@ -227,6 +229,15 @@ def draw(
227229 * "min_dyad_lw" (default: 1)
228230 * "max_dyad_lw" (default: 10)
229231
232+ Node-label styling (only used when ``node_labels`` is enabled);
233+ see :func:`draw_node_labels` for the full list.
234+
235+ Hyperedge-label styling (only used when ``hyperedge_labels`` is enabled);
236+ see :func:`draw_hyperedge_labels` for the full list.
237+
238+ Passing an argument that does not belong to any of these three groups
239+ raises a ``TypeError``.
240+
230241 Returns
231242 -------
232243 ax : matplotlib Axes
@@ -247,6 +258,12 @@ def draw(
247258 >>> H.add_edges_from([[1,2,3],[3,4],[4,5,6,7],[7,8,9,10,11]])
248259 >>> ax = xgi.draw(H, pos=xgi.barycenter_spring_layout(H))
249260
261+ Notes
262+ -----
263+ For finer control over node or hyperedge label appearance, call
264+ :func:`draw_node_labels` or :func:`draw_hyperedge_labels` directly after
265+ ``draw()``.
266+
250267 See Also
251268 --------
252269 draw_nodes
@@ -266,7 +283,29 @@ def draw(
266283 "max_node_lw" : 5 ,
267284 }
268285
269- settings .update (kwargs )
286+ # Split **kwargs into three non-overlapping buckets and validate upfront.
287+ # Doing this here — unconditionally and against all valid keys at once —
288+ # catches typos even when labels are off, and prevents cross-bucket confusion
289+ # (e.g. a valid edge-label kwarg being rejected by node-label validation).
290+ _settings_keys = set (settings )
291+ _node_label_keys = (
292+ signature (draw_node_labels ).parameters .keys ()
293+ - {"H" , "pos" , "ax_nodes" , "node_labels" }
294+ )
295+ _edge_label_keys = (
296+ signature (draw_hyperedge_labels ).parameters .keys ()
297+ - {"H" , "pos" , "ax_edges" , "hyperedge_labels" }
298+ )
299+ unknown = set (kwargs ) - (_settings_keys | _node_label_keys | _edge_label_keys )
300+ if unknown :
301+ raise TypeError (
302+ f"draw() got unexpected keyword argument(s): { ', ' .join (sorted (unknown ))} "
303+ )
304+ settings_kwargs = {k : v for k , v in kwargs .items () if k in _settings_keys }
305+ node_label_kwargs = {k : v for k , v in kwargs .items () if k in _node_label_keys }
306+ edge_label_kwargs = {k : v for k , v in kwargs .items () if k in _edge_label_keys }
307+
308+ settings .update (settings_kwargs )
270309
271310 ax , pos = _draw_init (H , ax , pos )
272311
@@ -293,7 +332,7 @@ def draw(
293332 max_order = max_order ,
294333 hyperedge_labels = hyperedge_labels ,
295334 rescale_sizes = rescale_sizes ,
296- ** kwargs ,
335+ ** edge_label_kwargs ,
297336 )
298337
299338 elif isinstance (H , Hypergraph ):
@@ -319,7 +358,7 @@ def draw(
319358 hull = hull ,
320359 radius = radius ,
321360 rescale_sizes = rescale_sizes ,
322- ** kwargs ,
361+ ** edge_label_kwargs ,
323362 )
324363 else :
325364 raise XGIError ("The input must be a SimplicialComplex or Hypergraph" )
@@ -340,7 +379,7 @@ def draw(
340379 params = settings ,
341380 node_labels = node_labels ,
342381 rescale_sizes = rescale_sizes ,
343- ** kwargs ,
382+ ** node_label_kwargs ,
344383 )
345384
346385 # compute axis limits
@@ -467,7 +506,9 @@ def draw_nodes(
467506 }
468507
469508 settings .update (params )
470- settings .update (kwargs )
509+ # Only absorb recognised settings keys from kwargs so that label kwargs
510+ # passed via a direct call to draw_nodes() don't pollute the settings dict.
511+ settings .update ({k : v for k , v in kwargs .items () if k in settings })
471512
472513 ax , pos = _draw_init (H , ax , pos )
473514
@@ -523,15 +564,9 @@ def draw_nodes(
523564 )
524565
525566 if node_labels :
526- # Get all valid keywords by inspecting the signatures of draw_node_labels
527- valid_label_kwds = signature (draw_node_labels ).parameters .keys ()
528- # Remove the arguments of this function (draw_networkx)
529- valid_label_kwds = valid_label_kwds - {"H" , "pos" , "ax" , "node_labels" }
530- if any ([k not in valid_label_kwds for k in kwargs ]):
531- invalid_args = ", " .join ([k for k in kwargs if k not in valid_label_kwds ])
532- raise ValueError (f"Received invalid argument(s): { invalid_args } " )
533- label_kwds = {k : v for k , v in kwargs .items () if k in valid_label_kwds }
534- draw_node_labels (H , pos , node_labels , ax_nodes = ax , ** label_kwds )
567+ # kwargs here are already validated and filtered to node-label keys by
568+ # draw() when called from there; for direct calls they are passed as-is.
569+ draw_node_labels (H , pos , node_labels , ax_nodes = ax , ** kwargs )
535570
536571 # compute axis limits
537572 _update_lims (pos , ax )
@@ -694,7 +729,9 @@ def draw_hyperedges(
694729 }
695730
696731 settings .update (params )
697- settings .update (kwargs )
732+ # Only absorb recognised settings keys from kwargs so that label kwargs
733+ # passed via a direct call to draw_hyperedges() don't pollute the settings dict.
734+ settings .update ({k : v for k , v in kwargs .items () if k in settings })
698735
699736 ax , pos = _draw_init (H , ax , pos )
700737
@@ -819,15 +856,9 @@ def draw_hyperedges(
819856 ax .add_collection (edge_collection )
820857
821858 if hyperedge_labels :
822- # Get all valid keywords by inspecting the signatures of draw_node_labels
823- valid_label_kwds = signature (draw_hyperedge_labels ).parameters .keys ()
824- # Remove the arguments of this function (draw_networkx)
825- valid_label_kwds = valid_label_kwds - {"H" , "pos" , "ax" , "hyperedge_labels" }
826- if any ([k not in valid_label_kwds for k in kwargs ]):
827- invalid_args = ", " .join ([k for k in kwargs if k not in valid_label_kwds ])
828- raise ValueError (f"Received invalid argument(s): { invalid_args } " )
829- label_kwds = {k : v for k , v in kwargs .items () if k in valid_label_kwds }
830- draw_hyperedge_labels (H , pos , hyperedge_labels , ax_edges = ax , ** label_kwds )
859+ # kwargs here are already validated and filtered to edge-label keys by
860+ # draw() when called from there; for direct calls they are passed as-is.
861+ draw_hyperedge_labels (H , pos , hyperedge_labels , ax_edges = ax , ** kwargs )
831862
832863 # compute axis limits
833864 _update_lims (pos , ax )
0 commit comments