2
$\begingroup$

I have the following dataset:

partitionedPts = {{{{180, 100}, {274.33`, 100}}, {{274.33`, 
     98.90028`}, {274.33`, 98.02906`}}, {{180, 98.90028`}, {274.33`, 
     98.90028`}}}, {{{274.33`, 100}, {457.645`, 100}}, {{457.645`, 
     98.02906`}, {457.645`, 85.9109`}}, {{274.33`, 
     98.02906`}, {457.645`, 98.02906`}}}, {{{457.645`, 
     100}, {492.329`, 100}}, {{492.329`, 85.9109`}, {492.329`, 
     81.68262`}}, {{457.645`, 85.9109`}, {492.329`, 
     85.9109`}}}, {{{492.329`, 100}, {681.938`, 100}}, {{681.938`, 
     81.68262`}, {681.938`, 80.13062`}}, {{492.329`, 
     81.68262`}, {681.938`, 81.68262`}}}, {{{681.938`, 
     100}, {862.401`, 100}}, {{862.401`, 80.13062`}, {862.401`, 
     78.64416`}}, {{681.938`, 80.13062`}, {862.401`, 
     80.13062`}}}, {{{862.401`, 100}, {985.038`, 100}}, {{985.038`, 
     78.64416`}, {985.038`, 77.63547`}}, {{862.401`, 
     78.64416`}, {985.038`, 78.64416`}}}, {{{985.038`, 
     100}, {1087.85`, 100}}, {{1087.85`, 77.63547`}, {1087.85`, 
     76.49579`}}, {{985.038`, 77.63547`}, {1087.85`, 
     77.63547`}}}, {{{1087.85`, 100}, {1117.983`, 100}}, {{1117.983`, 
     76.49579`}, {1117.983`, 76.47131`}}, {{1087.85`, 
     76.49579`}, {1117.983`, 76.49579`}}}}

and currently this code to transform it into gnuplot code to print arrows:

arrows = 
 StringJoin["set arrow " ~~ #[[1]] ~~ " " ~~ #[[2]]] & /@ 
  Transpose[{Map[ToString, 
       Range@Length@#, {-1}], #} &@(StringJoin[
        "from first " ~~ #[[1, 1]] ~~ "," ~~ #[[1, 2]] ~~ 
         " to first " ~~ #[[2, 1]] ~~ "," ~~ #[[2, 2]]] & /@ 
      Flatten[Map[ToString, partitionedPts, {-1}], 1])]

Which produces:

{"set arrow 1 from first 180,100 to first 274.33,100", 
 "set arrow 2 from first 274.33,98.9003 to first 274.33,98.0291",...}

But I would like to produce this one:

{"set arrow 1 arrowstyle 1 from first 180,100 to first 274.33,100", 
 "set arrow 2 arrowstyle 2 from first 274.33,98.9003 to first 274.33,98.0291",
 "set arrow 3 arrowstyle 3 from first 180,98.9003 to first 274.33,98.9003", 
 "set arrow 4 arrowstyle 1 from first 274.33,100 to first 457.645,100", 
 "set arrow 5 arrowstyle 2 from first 457.645,98.0291 to first 457.645,85.9109", 
 "set arrow 6 arrowstyle 3 from first 274.33,98.0291 to first 457.645,98.0291", ...}

I am trying something along the lines (i was thinking of named slots one would use the array partitionedPts and the other would just use {1,2,3}:

Outer[StringJoin[
   "arrowstyle "~~#2~~" from first " ~~ #1[[1, 1]] ~~ "," ~~ #1[[1, 2]] ~~ 
    " to first " ~~ #1[[2, 1]] ~~ "," ~~ #1[[2, 2]]] &, 
 Transpose[Map[ToString, partitionedPts, {-1}]], {1, 2, 3}]

I have gone through all the options that I know but I admit, this is the type of problem that i always get stuck with, when i have multiple list of variable depth. This is so trivial to do with for loops and so complicated in mathematica's illegible @/_& style but I prefer to learn the mathematica way.

$\endgroup$
2
  • $\begingroup$ Dimensions@partitionedPts gives {8, 3, 2, 2}. In your title you refer to variable depth lists. Please elaborate. $\endgroup$
    – Syed
    Sep 16, 2022 at 6:56
  • $\begingroup$ @Syed Well and the dimension of {1,2,3} is {3} and I want it to insert inside one of the diemnsions of partitionedPts and repeat. $\endgroup$
    – atapaka
    Sep 16, 2022 at 13:40

2 Answers 2

3
$\begingroup$

You can use StringTemplate and MapIndexed.

With partitionedPts as in OP and

stmp =
  StringTemplate[
   "set arrow `1` arrowstyle `2` from first `3` to first `4`"
   , InsertionFunction -> (t |-> ExportString[{t}, "Table", "FieldSeparators" -> ","])
   ];

Then

Module[{i = 0},
 stmp @@@
  Flatten[
   MapIndexed[{val, idx} |-> {++i, Last@idx, Sequence @@ val}
    , partitionedPts
    , {2}]
   , 1]
 ]
{
 "set arrow 1 arrowstyle 1 from first 180,100 to first 274.33,100",
 "set arrow 2 arrowstyle 2 from first 274.33,98.90028 to first 274.33,98.02906", 
 "set arrow 3 arrowstyle 3 from first 180,98.90028 to first 274.33,98.90028", 
 "set arrow 4 arrowstyle 1 from first 274.33,100 to first 457.645,100", 
 ...
 "set arrow 24 arrowstyle 3 from first 1087.85,76.49579 to first 1117.983,76.49579"
}

Hope this helps.

$\endgroup$
2
  • $\begingroup$ This is a very nice solution, it took me some time to decode. The only thing i do not understand, you are using the preincrement ++i which i cannot help but see only working if there is some loop (yet internal, but loop nonetheless). So would it be so unwise to write this as a loop?(I am asking since there is a nice older faq here which almost forces a dogma to avoid any loops in Mathematica) $\endgroup$
    – atapaka
    Sep 16, 2022 at 14:18
  • $\begingroup$ @atapaka Try writing it as a loop and compare performance with AbsoluteTiming. Mapping and applying is generally faster in Wolfram Language. $\endgroup$
    – Edmund
    Sep 17, 2022 at 0:57
2
$\begingroup$

I might try MapIndexed. This assumes that each sublist at the first level has length 3. It could be modified if that's not the case. To show how MapIndexed might work, let's test with a dummy function:

MapIndexed[f, partitionedPts, {2}]

This gives something that starts with

{{f[{{180, 100}, {274.33, 100}}, {1, 1}], f[{{274.33, 98.9003}, {274.33, 98.0291}}, {1, 2}], f[{{180, 98.9003}, {274.33, 98.9003}}, {1, 3}]} ...}

That looks promising. We get our coordinates and the part spec can be turned into the numbers you want. We can use this sample to help us specify a helper function that works on the right structure:

Describe[{pt1_, pt2_}, part_] := 
  StringForm[
    "set arrow style `` arrowstyle `` from first `` to first ``", 
    3 (part[[1]] - 1) + part[[2]], 
    part[[2]], 
    pt1, 
    pt2]

You can see the assumption of length 3 for the first level lists. Let's put this together:

MapIndexed[ToString@*Describe, partitionedPts, {2}]

You don't need the ToString if you just want to see a formatted result. The ToString normalizes the results into actual strings, and that might be more useful for subsequent processing. The result starts with

{{"set arrow style 1 arrowstyle 1 from first {180, 100} to first {274.33, 100}", "set arrow style 2 arrowstyle 2 from first {274.33, 98.9003} to first {274.33, 98.0291}", "set arrow style 3 arrowstyle 3 from first {180, 98.9003} to first {274.33, 98.9003}"} ... }
$\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.