@@ -25,6 +25,7 @@ def build_figure_py(
2525 layout_validator ,
2626 frame_validator ,
2727 subplot_nodes ,
28+ layout_array_nodes ,
2829):
2930 """
3031
@@ -47,6 +48,8 @@ def build_figure_py(
4748 FrameValidator instance
4849 subplot_nodes: list of str
4950 List of names of all of the layout subplot properties
51+ layout_array_nodes: list of PlotlyNode
52+ List of array nodes under layout that can be positioned using xref/yref
5053 Returns
5154 -------
5255 str
@@ -66,8 +69,10 @@ def build_figure_py(
6669 # ### Import base class ###
6770 buffer .write (f"from plotly.{ base_package } import { base_classname } \n " )
6871
69- # ### Import trace graph_obj classes ###
70- trace_types_csv = ", " .join ([n .name_datatype_class for n in trace_nodes ])
72+ # ### Import trace graph_obj classes / layout ###
73+ trace_types_csv = ", " .join (
74+ [n .name_datatype_class for n in trace_nodes ] + ["layout as _layout" ]
75+ )
7176 buffer .write (f"from plotly.graph_objs import ({ trace_types_csv } )\n " )
7277
7378 # Write class definition
@@ -358,14 +363,253 @@ def update_{plural_name}(
358363 return self"""
359364 )
360365
366+ # update annotations/shapes/images
367+ # --------------------------------
368+ for node in layout_array_nodes :
369+ singular_name = node .plotly_name
370+ plural_name = node .name_property
371+
372+ if singular_name == "image" :
373+ # Rename image to layout_image to avoid conflict with an image trace
374+ method_prefix = "layout_"
375+ else :
376+ method_prefix = ""
377+
378+ buffer .write (
379+ f"""
380+ def select_{ method_prefix } { plural_name } (
381+ self, selector=None, row=None, col=None, secondary_y=None
382+ ):
383+ \" \" \"
384+ Select { plural_name } from a particular subplot cell and/or { plural_name }
385+ that satisfy custom selection criteria.
386+
387+ Parameters
388+ ----------
389+ selector: dict or None (default None)
390+ Dict to use as selection criteria.
391+ Annotations will be selected if they contain properties corresponding
392+ to all of the dictionary's keys, with values that exactly match
393+ the supplied values. If None (the default), all { plural_name } are
394+ selected.
395+ row, col: int or None (default None)
396+ Subplot row and column index of { plural_name } to select.
397+ To select { plural_name } by row and column, the Figure must have been
398+ created using plotly.subplots.make_subplots. To select only those
399+ { singular_name } that are in paper coordinates, set row and col to the
400+ string 'paper'. If None (the default), all { plural_name } are selected.
401+ secondary_y: boolean or None (default None)
402+ * If True, only select { plural_name } associated with the secondary
403+ y-axis of the subplot.
404+ * If False, only select { plural_name } associated with the primary
405+ y-axis of the subplot.
406+ * If None (the default), do not filter { plural_name } based on secondary
407+ y-axis.
408+
409+ To select { plural_name } by secondary y-axis, the Figure must have been
410+ created using plotly.subplots.make_subplots. See the docstring
411+ for the specs argument to make_subplots for more info on
412+ creating subplots with secondary y-axes.
413+ Returns
414+ -------
415+ generator
416+ Generator that iterates through all of the { plural_name } that satisfy
417+ all of the specified selection criteria
418+ \" \" \"
419+ return self._select_annotations_like(
420+ "{ plural_name } ", selector=selector, row=row, col=col, secondary_y=secondary_y
421+ )
422+
423+ def for_each_{ method_prefix } { singular_name } (
424+ self, fn, selector=None, row=None, col=None, secondary_y=None
425+ ):
426+ \" \" \"
427+ Apply a function to all { plural_name } that satisfy the specified selection
428+ criteria
429+
430+ Parameters
431+ ----------
432+ fn:
433+ Function that inputs a single { singular_name } object.
434+ selector: dict or None (default None)
435+ Dict to use as selection criteria.
436+ Traces will be selected if they contain properties corresponding
437+ to all of the dictionary's keys, with values that exactly match
438+ the supplied values. If None (the default), all { plural_name } are
439+ selected.
440+ row, col: int or None (default None)
441+ Subplot row and column index of { plural_name } to select.
442+ To select { plural_name } by row and column, the Figure must have been
443+ created using plotly.subplots.make_subplots. To select only those
444+ { plural_name } that are in paper coordinates, set row and col to the
445+ string 'paper'. If None (the default), all { plural_name } are selected.
446+ secondary_y: boolean or None (default None)
447+ * If True, only select { plural_name } associated with the secondary
448+ y-axis of the subplot.
449+ * If False, only select { plural_name } associated with the primary
450+ y-axis of the subplot.
451+ * If None (the default), do not filter { plural_name } based on secondary
452+ y-axis.
453+
454+ To select { plural_name } by secondary y-axis, the Figure must have been
455+ created using plotly.subplots.make_subplots. See the docstring
456+ for the specs argument to make_subplots for more info on
457+ creating subplots with secondary y-axes.
458+ Returns
459+ -------
460+ self
461+ Returns the Figure object that the method was called on
462+ \" \" \"
463+ for obj in self._select_annotations_like(
464+ prop='{ plural_name } ',
465+ selector=selector,
466+ row=row,
467+ col=col,
468+ secondary_y=secondary_y,
469+ ):
470+ fn(obj)
471+
472+ return self
473+
474+ def update_{ method_prefix } { plural_name } (
475+ self,
476+ patch,
477+ selector=None,
478+ row=None,
479+ col=None,
480+ secondary_y=None,
481+ **kwargs
482+ ):
483+ \" \" \"
484+ Perform a property update operation on all { plural_name } that satisfy the
485+ specified selection criteria
486+
487+ Parameters
488+ ----------
489+ patch: dict or None (default None)
490+ Dictionary of property updates to be applied to all { plural_name } that
491+ satisfy the selection criteria.
492+ selector: dict or None (default None)
493+ Dict to use as selection criteria.
494+ Traces will be selected if they contain properties corresponding
495+ to all of the dictionary's keys, with values that exactly match
496+ the supplied values. If None (the default), all { plural_name } are
497+ selected.
498+ row, col: int or None (default None)
499+ Subplot row and column index of { plural_name } to select.
500+ To select { plural_name } by row and column, the Figure must have been
501+ created using plotly.subplots.make_subplots. To select only those
502+ { singular_name } that are in paper coordinates, set row and col to the
503+ string 'paper'. If None (the default), all { plural_name } are selected.
504+ secondary_y: boolean or None (default None)
505+ * If True, only select { plural_name } associated with the secondary
506+ y-axis of the subplot.
507+ * If False, only select { plural_name } associated with the primary
508+ y-axis of the subplot.
509+ * If None (the default), do not filter { plural_name } based on secondary
510+ y-axis.
511+
512+ To select { plural_name } by secondary y-axis, the Figure must have been
513+ created using plotly.subplots.make_subplots. See the docstring
514+ for the specs argument to make_subplots for more info on
515+ creating subplots with secondary y-axes.
516+ **kwargs
517+ Additional property updates to apply to each selected { singular_name } . If
518+ a property is specified in both patch and in **kwargs then the
519+ one in **kwargs takes precedence.
520+
521+ Returns
522+ -------
523+ self
524+ Returns the Figure object that the method was called on
525+ \" \" \"
526+ for obj in self._select_annotations_like(
527+ prop='{ plural_name } ',
528+ selector=selector,
529+ row=row,
530+ col=col,
531+ secondary_y=secondary_y,
532+ ):
533+ obj.update(patch, **kwargs)
534+
535+ return self
536+ """
537+ )
538+ # Add layout array items
539+ buffer .write (
540+ f"""
541+ def add_{ method_prefix } { singular_name } (self"""
542+ )
543+ add_constructor_params (
544+ buffer ,
545+ node .child_datatypes ,
546+ prepend_extras = ["arg" ],
547+ append_extras = ["row" , "col" , "secondary_y" ],
548+ )
549+
550+ prepend_extras = [
551+ (
552+ "arg" ,
553+ f"instance of { node .name_datatype_class } or dict with "
554+ "compatible properties" ,
555+ )
556+ ]
557+ append_extras = [
558+ ("row" , f"Subplot row for { singular_name } " ),
559+ ("col" , f"Subplot column for { singular_name } " ),
560+ ("secondary_y" , f"Whether to add { singular_name } to secondary y-axis" ),
561+ ]
562+ add_docstring (
563+ buffer ,
564+ node ,
565+ header = f"Create and add a new { singular_name } to the figure's layout" ,
566+ prepend_extras = prepend_extras ,
567+ append_extras = append_extras ,
568+ return_type = fig_classname ,
569+ )
570+
571+ # #### Function body ####
572+ buffer .write (
573+ f"""
574+ new_obj = _layout.{ node .name_datatype_class } (arg,
575+ """
576+ )
577+
578+ for i , subtype_node in enumerate (node .child_datatypes ):
579+ subtype_prop_name = subtype_node .name_property
580+ buffer .write (
581+ f"""
582+ { subtype_prop_name } ={ subtype_prop_name } ,"""
583+ )
584+
585+ buffer .write ("""**kwargs)""" )
586+
587+ buffer .write (
588+ f"""
589+ return self._add_annotation_like(
590+ '{ singular_name } ',
591+ '{ plural_name } ',
592+ new_obj,
593+ row=row,
594+ col=col,
595+ secondary_y=secondary_y,
596+ )"""
597+ )
598+
361599 # Return source string
362600 # --------------------
363601 buffer .write ("\n " )
364602 return buffer .getvalue ()
365603
366604
367605def write_figure_classes (
368- outdir , trace_node , data_validator , layout_validator , frame_validator , subplot_nodes
606+ outdir ,
607+ trace_node ,
608+ data_validator ,
609+ layout_validator ,
610+ frame_validator ,
611+ subplot_nodes ,
612+ layout_array_nodes ,
369613):
370614 """
371615 Construct source code for the Figure and FigureWidget classes and
@@ -385,9 +629,10 @@ def write_figure_classes(
385629 LayoutValidator instance
386630 frame_validator : CompoundArrayValidator
387631 FrameValidator instance
388- subplot_nodes: list of str
632+ subplot_nodes: list of PlotlyNode
389633 List of names of all of the layout subplot properties
390-
634+ layout_array_nodes: list of PlotlyNode
635+ List of array nodes under layout that can be positioned using xref/yref
391636 Returns
392637 -------
393638 None
@@ -420,6 +665,7 @@ def write_figure_classes(
420665 layout_validator ,
421666 frame_validator ,
422667 subplot_nodes ,
668+ layout_array_nodes ,
423669 )
424670
425671 # ### Format and write to file###
0 commit comments