9
$\begingroup$

If the size of an output expression is larger than threshold ByteCount, the front end will display an abbreviated version of it by producing an OutputSizeLimit object to avoid spending too much time on making boxes out of the full expression:

Array[x, 10000]

enter image description here

The boxes are made only when the "show all" button is pressed.

How can this behavior of defering the making of boxes be extended to other forms of output, like in a SummaryBox?

Consider the SummaryBox form of MyObject defined as

ClearAll[MyObject];
MyObject /:  MakeBoxes[obj : MyObject[asc_], form_] := 
  Module[{above, below}, 
    above = {{BoxForm`SummaryItem[{"Name: ", asc["Name"]}], SpanFromLeft}, 
             {BoxForm`SummaryItem[{"Variables: ", asc["Variables"]}],  
              BoxForm`SummaryItem[{"Length: ", asc["Length"]}]}};
    below = {BoxForm`SummaryItem[{"Date: ", asc["Date"]}],
             BoxForm`SummaryItem[{"Metadata: ", asc[MetaInformation]}]};

    BoxForm`ArrangeSummaryBox[MyObject,obj, Null,above,below,form]
  ];

Then the following expression will take a long time (like 5 full seconds) to appear on screen

Table[MyObject[<|"Name" -> "My particular object",
     "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> Today, 
     MetaInformation -> Array[x, 10000]|>], 20]

enter image description here

because, even though it is not displayed explicitly, it's presumably spending a lot of time making the boxes for each Array (as part of MetaInformation).

Is there a way to defer the making of boxes only to when the + button is pressed, like when the "show all" button is pressed in an OutputSizeLimit object?

The answer does not need to be given specifically in terms of SummaryBox. A simple dynamic front end object illustrating how it can be done in principle would suffice. I'm looking for key FrontEnd functions that can be used to defer the making of boxes.

$\endgroup$
  • 1
    $\begingroup$ You could try BoxForm`SummaryItem[{"Metadata: ", Dynamic @ asc[MetaInformation]}], which cuts the time in half for me. Still pretty slow, though. $\endgroup$ – Carl Woll Jun 4 '18 at 21:02
  • $\begingroup$ Unfortunately it's not actually the making of the boxes that's the killer. It's the display of them. For some reason the FE itself is doing this incredibly slowly (and there's not much I can think of to speed this up). As confirmation use Carl Woll's Dynamic @ trick and then run it through AbsoluteTiming @ ToBoxes. It takes a fraction of a second. Displaying it still takes like 3. $\endgroup$ – b3m2a1 Jun 6 '18 at 23:09
  • $\begingroup$ But if it's hidden behind the + it doesn't need to display it. What exactly is the part you say is taking a long time? $\endgroup$ – QuantumDot Jun 6 '18 at 23:23
  • $\begingroup$ @QuantumDot I don't know what it's doing, maybe making all those DynamicModuleBoxes. But the ToBoxes takes 0.60s and putting the things on screen takes 2.09, even with the Dynamic and hidden stuff. It might simply need to pass too much data. I think that might actually be it, as dropping the Array size to 100 to box creation and rendering times become much more similar. $\endgroup$ – b3m2a1 Jun 7 '18 at 0:15
5
+150
$\begingroup$

You can speed things up considerably by using a Dynamic as I suggested in the OP comments, and using RuleDelayed instead of Rule. Here is the MyObject definition using Dynamic:

ClearAll[MyObject];
MyObject /:  MakeBoxes[obj : MyObject[asc_], form_] := Module[{above, below}, 
    above = {
        {
        BoxForm`SummaryItem[{"Name: ", asc["Name"]}],
        SpanFromLeft
        }, 
        {
        BoxForm`SummaryItem[{"Variables: ", asc["Variables"]}],
        BoxForm`SummaryItem[{"Length: ", asc["Length"]}]
        }
    };
    below = {
        BoxForm`SummaryItem[{"Date: ", asc["Date"]}],
        BoxForm`SummaryItem[{"Metadata: ", Dynamic @ asc[MetaInformation]}]
    };

    BoxForm`ArrangeSummaryBox[MyObject,obj, Null,above,below,form]
]

And here is a list of MyObject objects using RuleDelayed instead of Rule:

list = Table[
    MyObject[
        <|
        "Name" -> "My particular object",
        "Length" -> 10,
        "Variables" -> {a, b, c},
        "Date" -> Today, 
        MetaInformation :> Array[x, 10000]
        |>
    ],
    20
];

Now, box generation is fast:

boxes = ToBoxes @ list; //AbsoluteTiming

{0.425972, Null}

And, rendering is fast:

start = AbsoluteTime[];
list

{MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]], MyObject[ Association[ "Name" -> "My particular object", "Length" -> 10, "Variables" -> {a, b, c}, "Date" -> DateObject[{2018, 6, 6}, "Day", "Gregorian", -7.], MetaInformation :> Array[x, 10000]]]}

AbsoluteTime[] - start

0.265248

Another idea is to not include the Metadata field in the summary box, but instead make it accessible with a property extractor, e.g.:

MyObject[asc_Association]["Metadata"] := asc[MetaInformation]
$\endgroup$
  • $\begingroup$ I think the RuleDelayed is doing the heavy lifting here (although of course the Dynamic is necessary). It looks like passing the data to and from the front-end is the rate limiting step here. So cutting down on the bytes passed is the key. $\endgroup$ – b3m2a1 Jun 7 '18 at 0:18
  • $\begingroup$ @b3m2a1 yes otoh Array[x, 10000] is an artificial example and in general it is the real data. So at the end the rule is, don't put there heavy stuff. I tried to use this trick here: mathematica.stackexchange.com/q/160938/5478 but Temporary symbols generated during typesetting are cleared differently than those from regular evaluation O_o $\endgroup$ – Kuba Jun 11 '18 at 9:52
  • $\begingroup$ @Kuba. Yes, this solution doesn't work for me because in my use case, the data Array[x, 10000] is already to be in evaluated form. $\endgroup$ – QuantumDot Jun 15 '18 at 0:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.