4
$\begingroup$

The Project

I am trying to dynamically turn on/off the display of data for a circos-esque plot that I generated.

Data Plot

The Code

I have data stored in mfData and a compiled list of data about that in mfIndex, primarily used for how many data sets there are (number of sectors, etc.).

Here are the steps that I have taken (3 & 4 are wrapped in Dynamic[]):

  1. Variables - I started the dynamic compilation of the code under the impression that I would need a variable for each sector set to True/False. So I generated n expressions and evaluated each to True to start off.

    vars = Table[ToExpression[StringJoin["sector", ToString[n], "=True"]], {n, 1, Length[mfIndex]}]

  2. Outer Rings - The rings are generated and wrapped in Button[] which switches the variable

    oRings = Table[Button[{color, Tooltip[Rotate[ring[outer_radius, inner_radius, angular_size], angle, {0, 0}], "Text"]}, (Symbol[StringJoin["sector", ToString[m]]] = Symbol[StringJoin["sector", ToString[m]]] /. {True -> False, False -> True})], {m, 1, Length[mfIndex]}]

  3. Choice - My hope was that the button directive would turn each variable to True/False when being clicked which would update pick and curves

    pick = Pick[Range[Length[mfIndex]],vars]

  4. Curves - The Bezier Curves are generated

    curves = Table[Table[BezierCurve[{pt1, pt2, pt3}],{n,1,Length[mfData[[n]]]}],{n,pick}]

The (Apparent) Problem

There are no errors when evaluated, but when I click on one of the rings an error comes up (I tried using both ToExpression[] and Symbol[] in the Outer Ring evaluation)

Set::write: Tag ToExpression in ToExpression[sectorm] is Protected. >>
Set::write: Tag Symbol in Symbol[sectorm] is Protected. >>

Meaning that when the Outer Ring code is evaluated the variables aren't being processed into their proper form... "sectorm" instead of {sector1, sector2, etc...}.

I know this is a bit long-winded to get to this question, but is there a better way to evaluate (compose) the variables? Or to accomplish the same thing or re-evaluating the display of data?

(I can provide more explanation if necessary, I tried to reduce this a bit for simplicity's sake...)



(Update) Minimal non-working example

(I think that copied over correctly...)

ring[o_, i_, s_, p_] := Module[{q, oP, iP, cut}, q = (s)/(2 Pi); oP = Table[{o Cos[k q 2 Pi/p], o Sin[k q 2 Pi/p]}, {k, 1, p}]; iP = Table[{i Cos[k q 2 Pi/p], i Sin[k q 2 Pi/p]}, {k, 1, p}]; cut = Polygon[Flatten[{oP, Reverse@iP}, 1]]; Return[cut]];

cir[x_, r_] := {r*Cos[x], r*Sin[x]}

Dynamic[vars = Table[ToExpression[StringJoin["sector", ToString[n]]], {n, 1, 8}]];

Table[ToExpression[StringJoin["sector", ToString[n], "=True"]], {n, 1, 8}];

points1 = Table[{RandomReal[{0 + m*(Pi/4), Pi/4 + m*(Pi/4) - Pi/64}], RandomReal[{0 + (m + 2)*(Pi/4), Pi/4 + (m + 2)*(Pi/4)}]}, {4}, {m, 0, 7}];

points2 = Table[Table[{points1[[n, o, 1]], If[Abs[points1[[n, o, 2]] - points1[[n, o, 1]]] > Pi, (points1[[n, o, 1]] + points1[[n, o, 2]])/2 + Pi, (points1[[n, o, 1]] + points1[[n, o, 2]])/2], points1[[n, o, 2]]}, {o, 1, 8}], {n, 1, 4}];

Dynamic[outRing = Table[Button[Rotate[ring[1.1, 1.05, Pi/4 - Pi/64, 1000], Pi/4*(n - 1), {0, 0}], (ToExpression[StringJoin["sector", ToString[n], "=", ToString[Not[Symbol[StringJoin["sector", ToString[n]]]]]]])], {n, 1, 8}]];

Dynamic[pick = Pick[Range[8], Table[Symbol[StringJoin["sector", ToString[n]]], {n, 1, 8}]]];

Dynamic[inCurve = Table[Table[BezierCurve[{cir[points2[[o, n, 1]], 1], cir[points2[[o, n, 2]], 0.3], cir[points2[[o, n, 3]], 1]}], {n, pick}], {o, 1, 4}]];

Dynamic[Graphics[{outRing, inCurve}]]

Simple working example

$\endgroup$
11
  • $\begingroup$ Change the swapper to something like ToExpression[ StringJoin["sector", ToString[m], "=", ToString[Not[Symbol[StringJoin["sector", ToString[m]]]]]]] $\endgroup$
    – ciao
    Feb 10, 2014 at 3:38
  • $\begingroup$ Nope... I get this: $RecursionLimit::reclim: Recursion depth of 1024 exceeded. >> $\endgroup$
    – MRN16
    Feb 10, 2014 at 3:46
  • $\begingroup$ Which I guess actually does get rid of the problem of the variable expression not evaluating... $\endgroup$
    – MRN16
    Feb 10, 2014 at 3:48
  • 1
    $\begingroup$ No, just one way of getting the job done - depending on what is going on in the table generation, things may not be evaluated in the way you think. Unfortunately, the non-working example really is non-working: it does not generate a proper graphics object when run... $\endgroup$
    – ciao
    Feb 10, 2014 at 4:59
  • 4
    $\begingroup$ It is hard to know where to start to comment on this but this is conceptually wrong -- for want of a better expression. The continued use of Dynamic followed by ; indicates a failure to understand what Dynamic does. Before proceeding any further on this please read all the relevant docs and tutorials on Dynamic. Dynamic only updates pixels on the screen. If you suppress output (i.e. no pixels) Dynamic is completely redundant. The same section of docs also address the use of e.g. Table[With {i=i},...],...] and when and why it is necessary. $\endgroup$ Feb 10, 2014 at 6:30

1 Answer 1

4
$\begingroup$

Here is one way to rewrite your minimal example. The main thing I have changed (apart from removing surplus Dynamics) is to use downvalues of a single symbol to store the state of each sector. That is, instead of creating symbols sector1, sector2 etc by string manipulation, use sector[1], sector[2] and so on.

The definitions of ring, cir, points1 and points2 are fine, so I've just copied them straight from the question:

ring[o_, i_, s_, p_] := Module[{q, oP, iP},
   q = (s)/(2 Pi);
   oP = Table[{o Cos[k q 2 Pi/p], o Sin[k q 2 Pi/p]}, {k, 1, p}]; 
   iP = Table[{i Cos[k q 2 Pi/p], i Sin[k q 2 Pi/p]}, {k, 1, p}];
   Polygon[Flatten[{oP, Reverse@iP}, 1]]];
cir[x_, r_] := {r*Cos[x], r*Sin[x]};
points1 = Table[{
    RandomReal[{0 + m*(Pi/4), Pi/4 + m*(Pi/4) - Pi/64}],
    RandomReal[{0 + (m + 2)*(Pi/4), Pi/4 + (m + 2)*(Pi/4)}]},
   {4}, {m, 0, 7}];
points2 = Table[{points1[[n, o, 1]],
    If[Abs[points1[[n, o, 2]] - points1[[n, o, 1]]] > Pi,
     (points1[[n, o, 1]] + points1[[n, o, 2]])/2 + Pi,
     (points1[[n, o, 1]] + points1[[n, o, 2]])/2], points1[[n, o, 2]]},
   {n, 1, 4}, {o, 1, 8}];

I calculate all the graphics primitives (curves and ring sectors) in advance:

curves = Table[BezierCurve[
    {cir[points2[[o, n, 1]], 1], cir[points2[[o, n, 2]], 0.3], cir[points2[[o, n, 3]], 1]}],
   {n, 8}, {o, 1, 4}];

rings = Table[Rotate[ring[1.1, 1.05, Pi/4 - Pi/64, 1000], Pi/4*(n - 1), {0, 0}], {n, 8}];

For the dynamic toggling of each sector, I use downvalues of the symbol sector to store the states. The buttons are defined so that the n'th button toggles sector[n] between True and False. Pick is used to select the elements of curves for which the corresponding sector[n] is True:

sector[_] = True;

outRing = Table[With[{n = n}, Button[rings[[n]], sector[n] = ! sector[n]]], {n, 8}];

Graphics[{outRing, Dynamic @ Pick[curves, Array[sector, 8]]}]
$\endgroup$
1
  • $\begingroup$ Thanks, definitely a much better approach than my... brutish forcing of symbol names. Thanks for the solution! $\endgroup$
    – MRN16
    Feb 11, 2014 at 1:21

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.