4
$\begingroup$

I have a plots with many lines and would like to be able to highlight lines when clicked (or on mouseover). When the data plotted is small this works well

styles = {Automatic, Automatic};
Dynamic@ListStepPlot[
  MapIndexed[
    EventHandler[#,
      {"MouseClicked" :> 
        (styles[[#2[[1]]]] = 
           styles[[#2[[1]]]] /. {Thick -> Automatic, Automatic -> Thick})}] &,
    {{1, 2, 3}, {2, 3, 5}}],
  PlotStyle -> styles]

Mathematica graphics

But my data is large and including the complete ListStepPlot inside Dynamic makes it very slow.

So I tried this, but it didn't work:

styles = {Automatic, Automatic};
ListStepPlot[
  MapIndexed[
    EventHandler[#,
      {"MouseClicked" :> 
        (styles[[#2[[1]]]] = 
           styles[[#2[[1]]]] /. {Thick -> Automatic, Automatic -> Thick})}] &,
    {{1, 2, 3}, {2, 3, 5}}],
  PlotStyle -> Dynamic[styles]]

I know that Dynamic can be used for some Plot options values but apparently not for PlotStyle. Is there a way to make this work efficiently for large data sets?

$\endgroup$
3
  • 1
    $\begingroup$ How fast/slow is this for your data: ListStepPlot[{{1, 2, 3}, {2, 3, 5}}, BaseStyle -> Thick] /. {styles__, l_Line} :> {styles, MouseAppearance[Dynamic@Mouseover[{Thin, l}, {Thick, l}], "LinkHand"]}? $\endgroup$
    – Kuba
    Aug 3, 2017 at 18:21
  • $\begingroup$ This works very well! I had never seen Dynamic being injected like that inside a graphics object. $\endgroup$ Aug 3, 2017 at 18:29
  • $\begingroup$ Oh @Kuba I see you got to the answer before I did $\endgroup$
    – b3m2a1
    Aug 3, 2017 at 18:31

3 Answers 3

5
$\begingroup$

Edit: more efficient and more flexible solution:

ListStepPlot[
    {{1, 2, 3}, {2, 3, 5}}, BaseStyle -> Thick
] /. {styles__, l_Line} :> DynamicModule[
    {edge = Thin}
  , {styles
    , Dynamic @ edge
    , MouseAppearance[
          EventHandler[
              l
            , "MouseClicked" :> (edge = edge /. {Thick -> Thin, Thin -> Thick} )
          ]
        , "LinkHand"
      ]
    }
 ]

Here is the old fix. Not the best as it doubles the size of the GraphicsBox:

ListStepPlot[
    {{1, 2, 3}, {2, 3, 5}}, BaseStyle -> Thick
] /. {styles__, l_Line} :> {
    styles
  , MouseAppearance[Dynamic@Mouseover[{Thin, l}, {Thick, l}], "LinkHand"]
}
$\endgroup$
2
$\begingroup$

Here's a way to do it by post-processing the Plot:

styleFloops =
  Map[RandomColor[] &, Range[2]];
styles =
  Map[Directive[ColorData[97][#], Thickness@Medium] &, Range[2]];
ListStepPlot[
  MapIndexed[
   EventHandler[#, {"MouseClicked" :> (styles[[#2[[1]]]] = 
         styles[[#2[[1]]]] /. {Thick -> Thickness@Medium, 
           Thickness@Medium -> Thick})}] &, {{1, 2, 3}, {2, 3, 5}}],
  PlotStyle ->
   styleFloops
  ] /.
 MapIndexed[
  Directive[a___, #, b___] :>
    Dynamic[Directive[a, styles[[First@#2]], b]] &,
  styleFloops
  ]

It works under the assumption that RandomColor will never be the Axes color and will never intersect. I think that's reasonable.

$\endgroup$
1
$\begingroup$

You can also use FlipView to flip through a list of styles on each mouse click:

styles = {Thin, AbsoluteThickness[3], Directive[Thick, Dashed]};

ListStepPlot[{{1, 2, 3}, {2, 3, 5}}] /. 
  l_Line :> MouseAppearance[FlipView @ Thread[{ styles, l}], "SampleStyle"] // Deploy

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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