Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am using the utility below for data comparison. However, with my real (more complex) charts the processing is quite slow, so setting the Pause time under 0.01 does not speed up the transition effect. Quite a few frames are needed for a smooth transition. I wonder if anyone can suggest ways to speed things up.

p1 = {{0.98, 1.02}, {1.29, 1.46}, {1.45, 1.8}, {1.69, 1.83},
   {2.01, 2.43}, {2.07, 2.43}, {2.39, 2.5}, {2.71, 2.99},
   {3.03, 3.51}, {3.33, 3.54}, {3.9, 3.91}, {4.2, 4.36},
   {4.46, 4.88}, {5.14, 4.62}, {5.48, 5.29}, {5.95, 5.96}};

p2 = {{1.04, 1.17}, {1.31, 1.61}, {1.51, 2.13}, {1.71, 2.06},
   {2.03, 2.61}, {2.15, 2.65}, {2.43, 2.65}, {2.61, 3.13},
   {2.95, 3.69}, {3.31, 3.84}, {3.92, 4.29}, {4.16, 4.69},
   {4.6, 5.14}, {5.14, 5.21}, {5.6, 5.66}, {5.99, 6.33}};

Deploy@Panel@DynamicModule[{op = 0, now = 0,
    a = ListPlot[p1, PlotRange -> {{0, 7}, {0, 7}},
      PlotStyle -> Directive[PointSize[0.02], Purple]],
    b = ListPlot[p2, PlotRange -> {{0, 7}, {0, 7}},
      PlotStyle -> Directive[PointSize[0.02], Blue]]},

   id = ImageDimensions@a;
   frames = 40;

   Column[{Row[{"Displayed data set:  ",
       Button["  p1  ", If[op == 1, now = 0;
         Do[op = Round[op - 1/frames, 0.001];
          FinishDynamic[]; Pause[0.01], {frames}]],
        Appearance -> Dynamic@If[op < 1 && now == 0, "Pressed", Automatic],
        ImageSize -> Medium],

       Button["  p2  ", If[op == 0, now = 1;
         Do[op = Round[op + 1/frames, 0.001];
          FinishDynamic[]; Pause[0.01], {frames}]],
        Appearance -> Dynamic@If[op > 0 && now == 1, "Pressed", Automatic],
        ImageSize -> Medium]}],

     Panel[Graphics[{White, Rectangle[{0, 0}, id],
        Inset[Dynamic@Insert[a, Opacity[Abs[op - 1]], {1, 1}], Center, Center, id],
        Inset[Dynamic@Insert[b, Opacity[op], {1, 1}], Center, Center, id]},
       PlotRange -> {{0, First@id}, {0, Last@id}}, ImageSize -> id],
      FrameMargins -> 15, Background -> White]}]]

enter image description here

share|improve this question

1 Answer 1

This is a good case to demonstrate how inefficient could the magic of Dynamic be. Evaluating the code below shows how many times Dynamic refreshes your plot. Click on the buttons to see.

p1 = {{0.98, 1.02}, {1.29, 1.46}, {1.45, 1.8}, {1.69, 1.83}, {2.01, 
    2.43}, {2.07, 2.43}, {2.39, 2.5}, {2.71, 2.99}, {3.03, 
    3.51}, {3.33, 3.54}, {3.9, 3.91}, {4.2, 4.36}, {4.46, 
    4.88}, {5.14, 4.62}, {5.48, 5.29}, {5.95, 5.96}};

p2 = {{1.04, 1.17}, {1.31, 1.61}, {1.51, 2.13}, {1.71, 2.06}, {2.03, 
    2.61}, {2.15, 2.65}, {2.43, 2.65}, {2.61, 3.13}, {2.95, 
    3.69}, {3.31, 3.84}, {3.92, 4.29}, {4.16, 4.69}, {4.6, 
    5.14}, {5.14, 5.21}, {5.6, 5.66}, {5.99, 6.33}};

Deploy@Panel@
  DynamicModule[{op = 0, now = 0, 
    a = ListPlot[p1, PlotRange -> {{0, 7}, {0, 7}}, 
      PlotStyle -> Directive[PointSize[0.02], Purple]], 
    b = ListPlot[p2, PlotRange -> {{0, 7}, {0, 7}}, 
      PlotStyle -> Directive[PointSize[0.02], Blue]], dCnt = 0}, 
   id = ImageDimensions@a;
   frames = 40;
   Column[{Row[{"Displayed data set:  ", 
       Button["  p1  ", If[op == 1, now = 0;
         Do[op = Round[op - 1/frames, 0.001];
          FinishDynamic[]; Pause[0.01], {frames}]];
        Print["Total Dynamic updates ", dCnt];, 
        Appearance -> 
         Dynamic@If[op < 1 && now == 0, "Pressed", Automatic], 
        ImageSize -> Medium], Button["  p2  ", If[op == 0, now = 1;
         Do[op = Round[op + 1/frames, 0.001];
          FinishDynamic[]; Pause[0.01], {frames}]]; 
        Print["Total Dynamic updates ", dCnt], 
        Appearance -> 
         Dynamic@If[op > 0 && now == 1, "Pressed", Automatic], 
        ImageSize -> Medium]}], 
     Panel[Graphics[{White, Rectangle[{0, 0}, id], 
        Inset[Dynamic[dCnt++; 
          Insert[a, Opacity[Abs[op - 1]], {1, 1}]], Center, Center, 
         id], Inset[Dynamic[dCnt++; Insert[b, Opacity[op], {1, 1}]], 
         Center, Center, id]}, 
       PlotRange -> {{0, First@id}, {0, Last@id}}, ImageSize -> id], 
      FrameMargins -> 15, Background -> White]}]]

There are many ways in which you could address your problem to improve speed, but regarding Dynamic, the most important thing is to make sure it only updates when appropriate. For that I suggest using a counter, TrackingSymbols, and SynchronousUpdating as demonstrated in the next example.

p1 = {{0.98, 1.02}, {1.29, 1.46}, {1.45, 1.8}, {1.69, 1.83}, {2.01, 
    2.43}, {2.07, 2.43}, {2.39, 2.5}, {2.71, 2.99}, {3.03, 
    3.51}, {3.33, 3.54}, {3.9, 3.91}, {4.2, 4.36}, {4.46, 
    4.88}, {5.14, 4.62}, {5.48, 5.29}, {5.95, 5.96}};

p2 = {{1.04, 1.17}, {1.31, 1.61}, {1.51, 2.13}, {1.71, 2.06}, {2.03, 
    2.61}, {2.15, 2.65}, {2.43, 2.65}, {2.61, 3.13}, {2.95, 
    3.69}, {3.31, 3.84}, {3.92, 4.29}, {4.16, 4.69}, {4.6, 
    5.14}, {5.14, 5.21}, {5.6, 5.66}, {5.99, 6.33}};

Deploy@Panel@
  DynamicModule[
   {op = 0, now = 0, 
    a = ListPlot[p1, PlotRange -> {{0, 7}, {0, 7}}, 
      PlotStyle -> Directive[PointSize[0.02], Purple]], 
    b = ListPlot[p2, PlotRange -> {{0, 7}, {0, 7}}, 
      PlotStyle -> Directive[PointSize[0.02], Blue]], refreshCnt = 0
    } 
   ,
   id = ImageDimensions@a;
   frames = 40;
   Column[{
     Row[{"Displayed data set:  ",
       Button["  p1  ",
        If[op == 1,
         now = 0;
         Do[op = Round[op - 1/frames, 0.001];, {frames}]
         ];
        refreshCnt++;
        Print["Total Dynamic updates ", refreshCnt]
        , Method -> "Queued"
        , 
        Appearance -> 
         Dynamic@If[op < 1 && now == 0, "Pressed", Automatic]
        , ImageSize -> Medium
        ]
       ,
       Button["  p2  ",
        If[op == 0,
         now = 1;
         Do[op = Round[op + 1/frames, 0.001], {frames}]
         ];
        refreshCnt++;
        Print["Total Dynamic updates ", refreshCnt]
        , Method -> "Queued"
        , 
        Appearance -> 
         Dynamic@If[op > 0 && now == 1, "Pressed", Automatic]
        , ImageSize -> Medium
        ]}]
     ,
     Panel[
      Dynamic[Refresh[
        Graphics[{White, Rectangle[{0, 0}, id], 
          Inset[Insert[a, Opacity[Abs[op - 1]], {1, 1}], Center, 
           Center, id], 
          Inset[Insert[b, Opacity[op], {1, 1}], Center, Center, id]}, 
         PlotRange -> {{0, First@id}, {0, Last@id}}, ImageSize -> id]
        , TrackedSymbols -> {refreshCnt}]
       ]
      , FrameMargins -> 15, Background -> White
      ]
     }]]
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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