20962096</ a >
20972097</ li >
20982098< li class ="md-nav__item ">
2099- < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.topo_sort ">
2099+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.cascade ">
21002100< span class ="md-ellipsis ">
21012101
2102- topo_sort
2102+ cascade
2103+
2104+ </ span >
2105+ </ a >
2106+ </ li >
2107+ < li class ="md-nav__item ">
2108+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.restrict ">
2109+ < span class ="md-ellipsis ">
2110+
2111+ restrict
2112+
2113+ </ span >
2114+ </ a >
2115+ </ li >
2116+ < li class ="md-nav__item ">
2117+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.counts ">
2118+ < span class ="md-ellipsis ">
2119+
2120+ counts
2121+
2122+ </ span >
2123+ </ a >
2124+ </ li >
2125+ < li class ="md-nav__item ">
2126+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.prune ">
2127+ < span class ="md-ellipsis ">
2128+
2129+ prune
21032130
21042131 </ span >
21052132</ a >
24622489</ a >
24632490</ li >
24642491< li class ="md-nav__item ">
2465- < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.topo_sort ">
2492+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.cascade ">
24662493< span class ="md-ellipsis ">
24672494
2468- topo_sort
2495+ cascade
2496+
2497+ </ span >
2498+ </ a >
2499+ </ li >
2500+ < li class ="md-nav__item ">
2501+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.restrict ">
2502+ < span class ="md-ellipsis ">
2503+
2504+ restrict
2505+
2506+ </ span >
2507+ </ a >
2508+ </ li >
2509+ < li class ="md-nav__item ">
2510+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.counts ">
2511+ < span class ="md-ellipsis ">
2512+
2513+ counts
2514+
2515+ </ span >
2516+ </ a >
2517+ </ li >
2518+ < li class ="md-nav__item ">
2519+ < a class ="md-nav__link " href ="#datajoint.diagram.Diagram.prune ">
2520+ < span class ="md-ellipsis ">
2521+
2522+ prune
24692523
24702524 </ span >
24712525</ a >
@@ -2512,9 +2566,15 @@ <h1 id="diagram">Diagram<a class="headerlink" href="#diagram" title="Permanent l
25122566< div class ="doc doc-object doc-module ">
25132567< a id ="datajoint.diagram "> </ a >
25142568< div class ="doc doc-contents first ">
2515- < p > Diagram visualization for DataJoint schemas.</ p >
2516- < p > This module provides the Diagram class for visualizing schema structure
2517- as directed acyclic graphs showing tables and their foreign key relationships.</ p >
2569+ < p > Diagram for DataJoint schemas.</ p >
2570+ < p > This module provides the Diagram class for constructing derived views of the
2571+ dependency graph. Diagram supports set operators (+, -, *) for selecting subsets
2572+ of tables, restriction propagation (cascade, restrict) for selecting subsets of
2573+ data, and inspection (counts, prune) for viewing those selections.</ p >
2574+ < p > Mutation operations (delete, drop) live in Table, which uses Diagram internally
2575+ for graph computation.</ p >
2576+ < p > Visualization methods (draw, make_dot, make_svg, etc.) require matplotlib and
2577+ pygraphviz. All other methods are always available.</ p >
25182578< div class ="doc doc-children ">
25192579< div class ="doc doc-object doc-class ">
25202580< h2 class ="doc doc-heading " id ="datajoint.diagram.Diagram ">
@@ -2589,7 +2649,13 @@ <h2 class="doc doc-heading" id="datajoint.diagram.Diagram">
25892649< details class ="note " open ="">
25902650< summary > Notes</ summary >
25912651< p > < code > diagram + 1 - 1</ code > may differ from < code > diagram - 1 + 1</ code > .
2592- Only tables loaded in the connection are displayed.</ p >
2652+ Only tables in activated schemas are displayed. To include tables in
2653+ downstream schemas that depend on the current schema but haven't been
2654+ explicitly activated::</ p >
2655+ < pre > < code > conn.dependencies.load_all_downstream()
2656+ dj.Diagram(schema) # now includes all downstream schemas
2657+ </ code > </ pre >
2658+ < p > < code > Diagram.cascade()</ code > calls < code > load_all_downstream()</ code > automatically.</ p >
25932659< p > Layout direction is controlled via < code > dj.config.display.diagram_direction</ code >
25942660(default < code > "TB"</ code > ). Use < code > dj.config.override()</ code > to change temporarily::</ p >
25952661< pre > < code > with dj.config.override(display_diagram_direction="LR"):
@@ -2736,13 +2802,66 @@ <h3 class="doc doc-heading" id="datajoint.diagram.Diagram.collapse">
27362802</ div >
27372803</ div >
27382804< div class ="doc doc-object doc-function ">
2739- < h3 class ="doc doc-heading " id ="datajoint.diagram.Diagram.topo_sort ">
2740- < span class ="doc doc-object-name doc-function-name "> topo_sort</ span >
2741- < a class ="headerlink " href ="#datajoint.diagram.Diagram.topo_sort " title ="Permanent link "> ¶</ a > </ h3 >
2742- < div class ="doc-signature highlight "> < pre > < span > </ span > < code > < span class ="nf "> topo_sort</ span > < span class ="p "> ()</ span >
2805+ < h3 class ="doc doc-heading " id ="datajoint.diagram.Diagram.cascade ">
2806+ < span class ="doc doc-object-name doc-function-name "> cascade</ span >
2807+ < span class ="doc doc-labels ">
2808+ < small class ="doc doc-label doc-label-classmethod "> < code > classmethod</ code > </ small >
2809+ </ span >
2810+ < a class ="headerlink " href ="#datajoint.diagram.Diagram.cascade " title ="Permanent link "> ¶</ a > </ h3 >
2811+ < div class ="doc-signature highlight "> < pre > < span > </ span > < code > < span class ="nf "> cascade</ span > < span class ="p "> (</ span > < span class ="n "> table_expr</ span > < span class ="p "> ,</ span > < span class ="n "> part_integrity</ span > < span class ="o "> =</ span > < span class ="s1 "> 'enforce'</ span > < span class ="p "> )</ span >
27432812</ code > </ pre > </ div >
27442813< div class ="doc doc-contents ">
2745- < p > Return nodes in topological order.</ p >
2814+ < p > Create a cascade diagram for a table expression.</ p >
2815+ < p > Builds a Diagram from the table's dependency graph, includes all
2816+ descendants (across all loaded schemas), and propagates the
2817+ restriction downstream using OR convergence — a child row is
2818+ affected if < em > any</ em > restricted ancestor taints it.</ p >
2819+ < p > < span class ="doc-section-title "> Parameters:</ span > </ p >
2820+ < table >
2821+ < thead >
2822+ < tr >
2823+ < th > Name</ th >
2824+ < th > Type</ th >
2825+ < th > Description</ th >
2826+ < th > Default</ th >
2827+ </ tr >
2828+ </ thead >
2829+ < tbody >
2830+ < tr class ="doc-section-item ">
2831+ < td >
2832+ < code > table_expr</ code >
2833+ </ td >
2834+ < td >
2835+ < code > < span title ="QueryExpression "> QueryExpression</ span > </ code >
2836+ </ td >
2837+ < td >
2838+ < div class ="doc-md-description ">
2839+ < p > A (possibly restricted) table expression
2840+ (e.g., < code > Session & 'subject_id=1'</ code > ).</ p >
2841+ </ div >
2842+ </ td >
2843+ < td >
2844+ < em > required</ em >
2845+ </ td >
2846+ </ tr >
2847+ < tr class ="doc-section-item ">
2848+ < td >
2849+ < code > part_integrity</ code >
2850+ </ td >
2851+ < td >
2852+ < code > < span title ="str "> str</ span > </ code >
2853+ </ td >
2854+ < td >
2855+ < div class ="doc-md-description ">
2856+ < p > < code > "enforce"</ code > (default), < code > "ignore"</ code > , or < code > "cascade"</ code > .</ p >
2857+ </ div >
2858+ </ td >
2859+ < td >
2860+ < code > 'enforce'</ code >
2861+ </ td >
2862+ </ tr >
2863+ </ tbody >
2864+ </ table >
27462865< p > < span class ="doc-section-title "> Returns:</ span > </ p >
27472866< table >
27482867< thead >
@@ -2754,11 +2873,149 @@ <h3 class="doc doc-heading" id="datajoint.diagram.Diagram.topo_sort">
27542873< tbody >
27552874< tr class ="doc-section-item ">
27562875< td >
2757- < code > < span title =" list " > list </ span > [ < span title ="str " > str </ span > ] </ code >
2876+ < code > < a class =" autorefs autorefs-internal " href =" #datajoint.diagram.Diagram " title ="Diagram (datajoint.diagram.Diagram) " > Diagram </ a > </ code >
27582877</ td >
27592878< td >
27602879< div class ="doc-md-description ">
2761- < p > Node names in topological order.</ p >
2880+ < p > New Diagram with cascade restrictions applied, trimmed to
2881+ the seed table and its affected descendants.</ p >
2882+ </ div >
2883+ </ td >
2884+ </ tr >
2885+ </ tbody >
2886+ </ table >
2887+ < p > < span class ="doc-section-title "> Examples:</ span > </ p >
2888+ < div class ="highlight "> < pre > < span > </ span > < code > < span class ="gp "> >>> </ span > < span class ="c1 "> # Preview cascade impact across all downstream schemas</ span >
2889+ < span class ="gp "> >>> </ span > < span class ="n "> dj</ span > < span class ="o "> .</ span > < span class ="n "> Diagram</ span > < span class ="o "> .</ span > < span class ="n "> cascade</ span > < span class ="p "> (</ span > < span class ="n "> Session</ span > < span class ="o "> &</ span > < span class ="s1 "> 'subject_id=1'</ span > < span class ="p "> )</ span > < span class ="o "> .</ span > < span class ="n "> counts</ span > < span class ="p "> ()</ span >
2890+ </ code > </ pre > </ div >
2891+ < div class ="highlight "> < pre > < span > </ span > < code > < span class ="gp "> >>> </ span > < span class ="c1 "> # Inspect the cascade subgraph</ span >
2892+ < span class ="gp "> >>> </ span > < span class ="n "> dj</ span > < span class ="o "> .</ span > < span class ="n "> Diagram</ span > < span class ="o "> .</ span > < span class ="n "> cascade</ span > < span class ="p "> (</ span > < span class ="n "> Session</ span > < span class ="o "> &</ span > < span class ="s1 "> 'subject_id=1'</ span > < span class ="p "> )</ span >
2893+ </ code > </ pre > </ div >
2894+ </ div >
2895+ </ div >
2896+ < div class ="doc doc-object doc-function ">
2897+ < h3 class ="doc doc-heading " id ="datajoint.diagram.Diagram.restrict ">
2898+ < span class ="doc doc-object-name doc-function-name "> restrict</ span >
2899+ < a class ="headerlink " href ="#datajoint.diagram.Diagram.restrict " title ="Permanent link "> ¶</ a > </ h3 >
2900+ < div class ="doc-signature highlight "> < pre > < span > </ span > < code > < span class ="nf "> restrict</ span > < span class ="p "> (</ span > < span class ="n "> table_expr</ span > < span class ="p "> )</ span >
2901+ </ code > </ pre > </ div >
2902+ < div class ="doc doc-contents ">
2903+ < p > Apply restrict condition and propagate downstream.</ p >
2904+ < p > AND at convergence — a child row is included only if it satisfies
2905+ < em > all</ em > restricted ancestors. Used for export. Can be chained.</ p >
2906+ < p > Cannot be called on a Diagram produced by < code > Diagram.cascade()</ code > .</ p >
2907+ < p > < span class ="doc-section-title "> Parameters:</ span > </ p >
2908+ < table >
2909+ < thead >
2910+ < tr >
2911+ < th > Name</ th >
2912+ < th > Type</ th >
2913+ < th > Description</ th >
2914+ < th > Default</ th >
2915+ </ tr >
2916+ </ thead >
2917+ < tbody >
2918+ < tr class ="doc-section-item ">
2919+ < td >
2920+ < code > table_expr</ code >
2921+ </ td >
2922+ < td >
2923+ < code > < span title ="QueryExpression "> QueryExpression</ span > </ code >
2924+ </ td >
2925+ < td >
2926+ < div class ="doc-md-description ">
2927+ < p > A restricted table expression.</ p >
2928+ </ div >
2929+ </ td >
2930+ < td >
2931+ < em > required</ em >
2932+ </ td >
2933+ </ tr >
2934+ </ tbody >
2935+ </ table >
2936+ < p > < span class ="doc-section-title "> Returns:</ span > </ p >
2937+ < table >
2938+ < thead >
2939+ < tr >
2940+ < th > Type</ th >
2941+ < th > Description</ th >
2942+ </ tr >
2943+ </ thead >
2944+ < tbody >
2945+ < tr class ="doc-section-item ">
2946+ < td >
2947+ < code > < a class ="autorefs autorefs-internal " href ="#datajoint.diagram.Diagram " title ="Diagram (datajoint.diagram.Diagram) "> Diagram</ a > </ code >
2948+ </ td >
2949+ < td >
2950+ < div class ="doc-md-description ">
2951+ < p > New Diagram with restrict conditions applied.</ p >
2952+ </ div >
2953+ </ td >
2954+ </ tr >
2955+ </ tbody >
2956+ </ table >
2957+ </ div >
2958+ </ div >
2959+ < div class ="doc doc-object doc-function ">
2960+ < h3 class ="doc doc-heading " id ="datajoint.diagram.Diagram.counts ">
2961+ < span class ="doc doc-object-name doc-function-name "> counts</ span >
2962+ < a class ="headerlink " href ="#datajoint.diagram.Diagram.counts " title ="Permanent link "> ¶</ a > </ h3 >
2963+ < div class ="doc-signature highlight "> < pre > < span > </ span > < code > < span class ="nf "> counts</ span > < span class ="p "> ()</ span >
2964+ </ code > </ pre > </ div >
2965+ < div class ="doc doc-contents ">
2966+ < p > Return affected row counts per table without modifying data.</ p >
2967+ < p > < span class ="doc-section-title "> Returns:</ span > </ p >
2968+ < table >
2969+ < thead >
2970+ < tr >
2971+ < th > Type</ th >
2972+ < th > Description</ th >
2973+ </ tr >
2974+ </ thead >
2975+ < tbody >
2976+ < tr class ="doc-section-item ">
2977+ < td >
2978+ < code > < span title ="dict "> dict</ span > [< span title ="str "> str</ span > , < span title ="int "> int</ span > ]</ code >
2979+ </ td >
2980+ < td >
2981+ < div class ="doc-md-description ">
2982+ < p > Mapping of full table name to affected row count.</ p >
2983+ </ div >
2984+ </ td >
2985+ </ tr >
2986+ </ tbody >
2987+ </ table >
2988+ </ div >
2989+ </ div >
2990+ < div class ="doc doc-object doc-function ">
2991+ < h3 class ="doc doc-heading " id ="datajoint.diagram.Diagram.prune ">
2992+ < span class ="doc doc-object-name doc-function-name "> prune</ span >
2993+ < a class ="headerlink " href ="#datajoint.diagram.Diagram.prune " title ="Permanent link "> ¶</ a > </ h3 >
2994+ < div class ="doc-signature highlight "> < pre > < span > </ span > < code > < span class ="nf "> prune</ span > < span class ="p "> ()</ span >
2995+ </ code > </ pre > </ div >
2996+ < div class ="doc doc-contents ">
2997+ < p > Remove tables with zero matching rows from the diagram.</ p >
2998+ < p > Without prior restrictions, removes physically empty tables.
2999+ After < code > restrict()</ code > , removes tables where the restricted query
3000+ yields zero rows. Cannot be used on a cascade Diagram (cascade
3001+ is for delete, where zero-count tables must remain in the graph
3002+ to handle concurrent inserts safely).</ p >
3003+ < p > < span class ="doc-section-title "> Returns:</ span > </ p >
3004+ < table >
3005+ < thead >
3006+ < tr >
3007+ < th > Type</ th >
3008+ < th > Description</ th >
3009+ </ tr >
3010+ </ thead >
3011+ < tbody >
3012+ < tr class ="doc-section-item ">
3013+ < td >
3014+ < code > < a class ="autorefs autorefs-internal " href ="#datajoint.diagram.Diagram " title ="Diagram (datajoint.diagram.Diagram) "> Diagram</ a > </ code >
3015+ </ td >
3016+ < td >
3017+ < div class ="doc-md-description ">
3018+ < p > New Diagram with empty tables removed.</ p >
27623019</ div >
27633020</ td >
27643021</ tr >
@@ -2795,6 +3052,27 @@ <h3 class="doc doc-heading" id="datajoint.diagram.Diagram.make_dot">
27953052</ tr >
27963053</ tbody >
27973054</ table >
3055+ < p > < span class ="doc-section-title "> Raises:</ span > </ p >
3056+ < table >
3057+ < thead >
3058+ < tr >
3059+ < th > Type</ th >
3060+ < th > Description</ th >
3061+ </ tr >
3062+ </ thead >
3063+ < tbody >
3064+ < tr class ="doc-section-item ">
3065+ < td >
3066+ < code > < a class ="autorefs autorefs-internal " href ="../errors/#datajoint.errors.DataJointError " title ="DataJointError (datajoint.errors.DataJointError) "> DataJointError</ a > </ code >
3067+ </ td >
3068+ < td >
3069+ < div class ="doc-md-description ">
3070+ < p > If pygraphviz/pydot is not installed.</ p >
3071+ </ div >
3072+ </ td >
3073+ </ tr >
3074+ </ tbody >
3075+ </ table >
27983076< details class ="note " open ="">
27993077< summary > Notes</ summary >
28003078< p > Layout direction is controlled via < code > dj.config.display.diagram_direction</ code > .
0 commit comments