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.

My question is how do I get dynamic legends (legends that turn data on/off) to work with Show? This is an extension of an old question here;

How to dynamically toggle curves on/off in a crowded Plot?

The application I have is to show data using a histogram and overlay many different distributions on top of it. Here is the code

randData = RandomVariate[NormalDistribution[], 10^3];
estDists = 
  EstimatedDistribution[randData, #] & /@ {NormalDistribution[mu, 
     sigma], StudentTDistribution[mu, sigma, 5]};
pdfs = PDF[#, x] & /@ estDists;
histPlot = Histogram[randData, Automatic, "ProbabilityDensity"];
distPlots = 
  Plot[pdfs, {x, Min[randData], Max[randData]}, 
   PlotLegends -> LineLegend[estDists]];
Show[{histPlot, distPlots}]

enter image description here

Now that's fine if you have 2 or 3 fitted distributions but if you have 10 it gets a little crowded. I found a very nice solution to this (see link above) that lets you click on the legend to toggle the curves on/off. I'll repeat the code here;

 (*Don't allow the Plot to evaluate yet*)
Attributes[DynamicLegend] = {HoldAll};

DynamicLegend[(plotfnc_)[f_, args___, (opts___)?OptionQ]] := 
 Module[{plot},(*evaluate the plot*)plot = plotfnc @@ {f, args, opts};
  (*if it does not have a legend,there is nothing to do*)
  If[! MatchQ[plot, _Legended], Return[plot]];
  DynamicModule[{(*get the directives and legend_text from the plot*)
    leg = plot[[2, 1]],(*by default,
    all plots are visible (not transparent)*)
    trans = Table[False, {Length[plot[[2, 1, 1, 1]]]}]}, 
   Dynamic[(*dynamically re-
    evaluate the plot with dynamic PlotStyles and PlotLegends*)
    plotfnc @@ {f, 
      args,(*prepend the directives with Transparent on dynamic \
switches*)PlotStyle -> 
       Table[With[{i = i}, 
         Flatten[Directive[
           If[TrueQ[trans[[i]]], Transparent, Directive[]], 
           leg[[1, 1, i]]], 1, Directive]], {i, 
         Length[leg[[1, 
           1]]]}],(*turn the legend_text's into Togglers and shove \
them back into the*)(*LineLegend structure.Also,
      delete the old directives in the*)(*LineLegend structure to \
force PlotLegends to pick up the new*)(*directives,
      so legend lines turn on/off with the curves*)
      PlotLegends -> 
       ReplacePart[leg, 
        Join[{{1, 1} -> Sequence[]}, 
         Table[With[{i = i}, {1, 2, i} -> 
            Toggler[
             Dynamic[trans[[i]]], {True -> leg[[1, 2, i]], 
              False -> leg[[1, 2, i]]}, FrameMargins -> 0]], {i, 
           Length[leg[[1, 2]]]}]]], 
      FilterRules[{opts}, 
       Except[{PlotStyle, 
         PlotLegends}]]},(*only need dynamic updates when trans is \
modified*)TrackedSymbols :> {trans}]]]

And can use it for a single plot

dynamicDistPlots = DynamicLegend[Plot[pdfs, {x, Min[randData], Max[randData]}, 
PlotLegends -> LineLegend[estDists]]]

But can't get it to work with the histogram

Show[{histPlot, dynamicDistPlots}]

I've had a play with applying the DynamicLegend to the Show and even tried to modify the DynamicLegend function (although I think that was a bit over by head). Any help would be appreciated as this would be a great tool to compare distributions.

share|improve this question
    
The problem is that dynamicDistPlots has Head DynamicModule and not Graphics. I would recommend allowing another input into dynamicDistPlots function which will allow you to pass in another graphics object directly. –  Jonathan Shock May 30 '13 at 1:42
    
Thanks Jonathan. So if I add another input for DynamicLegend which contains the histogram I can do the overlaying in that function. Seems to make sense, I'll try it out. –  Cam May 30 '13 at 5:14
add comment

1 Answer

up vote 3 down vote accepted

Will this work?

 DynamicModule[{x1 = True, x2 = True},
 randData = RandomVariate[NormalDistribution[], 10^3];
 estDists = 
  EstimatedDistribution[randData, #] & /@ {NormalDistribution[mu, 
     sigma], StudentTDistribution[mu, sigma, 5]};
 pdfs = PDF[#, x] & /@ estDists;
 histPlot = Histogram[randData, Automatic, "ProbabilityDensity"];
 Dynamic[distPlots = 
   Plot[pdfs, {x, Min[randData], Max[randData]}, 
    PlotStyle -> {If[x1, ColorData[1, 1], Opacity[0.1]], 
      If[x2, ColorData[1, 2], Opacity[0.1]]}, 
    PlotLegends -> {Button[estDists[[1]], x1 = ! x1], 
      Button[estDists[[2]], x2 = ! x2]}];
  Show[{histPlot, distPlots}]
  ]
 ]

Adding Appearance->None inside Button can make them more like just strings.

share|improve this answer
add comment

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.