8
$\begingroup$

Is it possible to visualize an array whose elements are angles as actual angles on a lattice grid? E.g., say, if the input is:

{{0, π, π}, {0, 0, π/2}, {π/2, 0, 3 π/3}}

then the graphical visualization of this array would be a 3x3 square lattice grid. On each node of the lattice, there will be an arrow (say, inside a circle) which shows the corresponding value from the array. In the above input, this would mean that the arrow at the first lattice-node would be 0, the second would be π, the third would be π, the fourth (i.e., the first node in the second raw of the lattice grid) would be 0, fifth 0, sixth π/2, etc.

$\endgroup$

4 Answers 4

15
$\begingroup$

It seems natural to convert each number into an arrow (representing a bearing, not an angle) by mapping an arrow-making function over the array. Placing the result into a GraphicsGrid provides options to visualize the lattice if desired.

angles = {{0, π, π}, {0, 0, π/2}, {π/2, 0, 3 π/3}};
GraphicsGrid[
 Map[Graphics[{
    LightGray, Circle[{0, 0}, 1], 
    Hue[#/(2 π), .6, .8], Thick, Arrowheads[Medium], Arrow[{{0, 0}, {Cos[#], Sin[#]}}]}] &, 
  angles, {2}]

Picture

Make it fancier, if you like, by souping up the arguments to Graphics. Here I have added another graphical element, hue, to assist in the visual discrimination.


As other answers accumulate it is apparent some explanation of this one may be helpful. When the matrix is small, there's not much objectionable to using complex, highly-decorated, or garish (saturated, heavily painted) graphics: chacun a son gout. For larger matrices, though, the point to replacing values with "glyphs," such as arrows, is to be able to visualize patterns. Cleveland et al., Tufte, MacEachren, and many others have shown through theory and experiment how to create effective visualizations: that is, ones that are accurately, quickly, and quantitatively interpreted. Their principles more or less amount to removing inessential material (Tufte's data-ink ratio maximization principle is explicit about this) and representing the numbers using effective graphic symbolization. The method offered in this answer is intended to show how to create effective visualizations on larger data quickly. To see the possibilities, I offer this variation of the problem applied to a larger matrix:

angles = 2 π ImageData[ImageAdjust[Blur[RandomImage[1, {40, 25}], 8], 4]];
GraphicsGrid[
 Map[Graphics[{Hue[#/(2 π), .6, .8], Thin, Arrowheads[Small], 
   Arrow[{{0, 0}, {Cos[#], Sin[#]}}]}] & , angles, {2}]];
Rasterize[%, ImageSize -> 600]

grid of arrows

$\endgroup$
10
  • $\begingroup$ All, thanks a lot for the quick responses! Both the solutions seem quite nice! However, when I obtain these graphics in Mathematica, I can't get the "Save Image As..." option. I want to save these graphics as PDF files. Do you know how one could do so? $\endgroup$
    – dbm
    Apr 24, 2013 at 2:35
  • $\begingroup$ @dbm that's strange, have you tried selecting the cell and go to the File menu option and select from there the choice "save selection as ..."? $\endgroup$
    – Spawn1701D
    Apr 24, 2013 at 8:14
  • $\begingroup$ @dbm, One trick is to apply Rasterize to the GraphicsGrid command: this converts it into an image that can be selected in toto and saved to a file. $\endgroup$
    – whuber
    Apr 24, 2013 at 12:57
  • 2
    $\begingroup$ FWIW, the technique here is effectively the same procedure applied for graphically displaying a circular time series. As Tufte might say, one would like to keep the "chart junk" to a complete minimum, so I think this is the best depiction among all the answers. (Sadly, I cannot give two upvotes.) $\endgroup$ Apr 24, 2013 at 13:41
  • 3
    $\begingroup$ +1 from me. Always nice to come across another devote of Tufte. It makes me optimistic that given enough time (and gentle promotion) we can find way to visualize the increasing complexity of the world in which we live. $\endgroup$
    – Jagra
    Sep 4, 2013 at 13:20
10
$\begingroup$

There is a new function AngularGauge in Mathematica 9, which might fit your requirement exactly.

chartFunc[num_] := AngularGauge[num, {0, 2 π},
  ScaleOrigin -> {0, 2 π},
  LabelStyle -> None,
  TicksStyle -> GrayLevel[.3],
  ScaleDivisions -> {36, 5},
  GaugeMarkers -> "ShinyHubNeedle",
  GaugeFrameElementFunction -> ({} &),
  ScaleRanges -> Partition[
    Append[Riffle[
      Partition[Range[0, 2 π, π/6], 2, 1],
      {{-.05, 0}, {-.1, 0}}], {-0.1, 0}],
    2, 2],
  ScaleRangeColorFunction -> (Lighter[ColorData["Rainbow"][#]] &)
  ]

Map[chartFunc, {{0, π, π}, {0, 0, π/2}, {π/2, 0, 3 π/3}}, {2}] // Grid

chartFunc

You can change the GaugeMarkers option to get many other kinds of needles.

Edit

As the code above is how I understand OP's question, that OP might actually want some fancy indicators which are not quantitative but qualitative, inspired by whuber's answer, and noticed that OP is using Mathematica 7.2, here is another built-in function ListVectorPlot, which is first introduced in version 7, for the required purpose:

chartFunc2[data_, size_] := ListVectorPlot[
  Map[{Cos[#], Sin[#]} &, Reverse[data]\[Transpose], {2}],
  VectorColorFunction -> Function[{x, y, vx, vy, n},
    Hue[
     If[vy < .5, 1 - #, #] &[ArcCos[2 vx - 1]/(2 π)],
     .6, .8]],
  VectorStyle -> "CircleArrow",
  VectorScale -> {size, 1, None},
  VectorPoints -> All,
  AspectRatio -> Automatic]

Usage:

chartFunc2[{{0, π, π}, {0, 0, π/2}, {π/2, 0, 3 π/3}}, .3]

chartFunc2 original array

angles = 2 π ImageData[ImageAdjust[Blur[RandomImage[1, {40, 25}], 8], 4]];
chartFunc2[angles, .015]

chartFunc2 large array

$\endgroup$
4
  • 2
    $\begingroup$ That's very pretty. To my eye, though, the crucial information--the orientation represented by each number--is lost within the decorative elements. $\endgroup$
    – whuber
    Apr 24, 2013 at 13:22
  • $\begingroup$ @whuber That's how I understand OP's question, in case what OP wants are actually some fancy indicators which are not quantitative but qualitative. btw you can always use different settings for GaugeMarkers, ScaleRanges, etc for a clearer appearance. $\endgroup$
    – Silvia
    Apr 24, 2013 at 15:49
  • $\begingroup$ Everybody is using the same random image (sort of). :D $\endgroup$
    – BoLe
    Apr 24, 2013 at 17:10
  • $\begingroup$ @whuber The angular data is colored. But arrows could be dropped perhaps. $\endgroup$
    – BoLe
    Apr 24, 2013 at 17:13
7
$\begingroup$

First you have to define a function that will create the arrow inside the circle for every given angle:

arr[th_] := Show[PolarPlot[1, {θ, 0, 2 π}, PlotStyle -> Red, Axes -> None], 
                 Graphics[{Blue, Thick, Arrow[{{0, 0}, Normalize[{Cos[th], Sin[th]}]}]}]]

then, using Map you apply that function to each coefficient of the matrix :

Map[arr, {{0, π, π}, {0, 0,π/2}, {π/2, 0, 3π/3}}, {2}]//TableForm

enter image description here


Following David Carraher's comment, if you want angles you can use the function

arr2[th_] := PieChart[{Mod[th, 2 π/(2 π), (2 π - Mod[th, 2 π])/(2 π)},
                      ChartStyle -> {Cyan, LightGray}, SectorOrigin -> 0]

Now,

Map[arr2, {{0, π, π}, {0, 0,π/2}, {π/2, 0, 3π/3}}, {2}]//TableForm

enter image description here

and combining both:

arr3[th_] := Show[PieChart[{Mod[th, 2 π]/(2 π), (2 π - Mod[th, 2 π])/(2 π)}, ChartStyle -> {Cyan, LightGray}, SectorOrigin -> 0,    
                  ChartStyle -> Graphics[{Blue, Thick, Arrow[{{0, 0}, {1, 0}}]}]],   
           Graphics[{{Blue, Thick, Arrow[{{0, 0}, {Cos[th], Sin[th]}}]}, 
           {Blue, Thick, Arrow[{{0, 0}, {1, 0}}]}}]]

Map[arr3, {{0, π, π}, {0, 0,π/2}, {π/2, 0, 3π/3}}, {2}]//TableForm

enter image description here

$\endgroup$
4
  • $\begingroup$ You have only drawn a single arm. To display an angle, one needs two arms and a symbol to show the sweep from one arm to the other. $\endgroup$
    – DavidC
    Apr 23, 2013 at 22:29
  • 1
    $\begingroup$ I'm sure you merely forgot, but Normalize[{Cos[th], Sin[th]}] is redundant, you see... you know, because $\cos^2 x+\sin^2 x=1$? $\endgroup$ Apr 23, 2013 at 22:36
  • $\begingroup$ @DavidCarraher the OP mentions an arrow inside a circle but its a good idea. $\endgroup$
    – Spawn1701D
    Apr 23, 2013 at 22:47
  • $\begingroup$ @J.M. it depends on what the first version of the command was. For instance if the initial plan was to use {1,Tan[th]} to give an example. But I think I will leave it for anyone that cares for a short 101 in trigonometry. $\endgroup$
    – Spawn1701D
    Apr 23, 2013 at 23:23
7
$\begingroup$

MapIndexed gives coordinates for drawing on a single canvas.

disks[angles_List] :=
 Graphics[MapIndexed[{
     Orange, Disk[#2, .3],
     Blue, Disk[#2, .3, {0, #1}]} &, angles, {2}]]

disks[{{0, Pi, Pi}, {0, 0, Pi/2}, {Pi/2, 0, 3 Pi/3}}]

angels1

disks[RandomReal[{0, 2 Pi}, {3, 3}]]

angels2


Following @whuber, and using a built-in function:

angles = 2 Pi ImageData[
    ImageAdjust[Blur[RandomImage[1, {40, 25}], 8], 4]];

ListVectorPlot[
 Map[{Cos[#], Sin[#]} &, Transpose@angles, {2}],
 VectorPoints -> All,
 VectorScale -> .02,
 AspectRatio -> Automatic]

vector plot

$\endgroup$
7
  • $\begingroup$ +1 for using a single Graphics expression $\endgroup$
    – Mr.Wizard
    Apr 24, 2013 at 13:29
  • $\begingroup$ The ListVectorPlot is good insofar as it addresses this particular question (+1). However, it is more difficult to generalize to other glyphs (which can acquire myriad shapes and characteristics, such as Chernoff faces) than your original solution, which is why I think your first approach should be favored. $\endgroup$
    – whuber
    Apr 24, 2013 at 16:18
  • $\begingroup$ I was wondering if someone would use ListVectorPlot. +1 $\endgroup$
    – rcollyer
    Apr 24, 2013 at 16:49
  • $\begingroup$ All, The plots look awesome! I have a very related question and I don't know if I should put a new question for it. The question is: how would you color the same plot according to some function of angles at each node. Say, at the node [i,j], I want to compute a function f[i,j] (to be more specific, f[i_,j_]:=Cos[angles[[i + 1, j]] - angles[[i, j]]]; with all angles[[n+1,i_]]:=angles[[1,i]] and angles[[i_,n+1]]:=angles[[i,1]], i.e., the boundary conditions)? In all the above codes, Hue is used for the angles themselves but extracting the nearby angles seems more involved? $\endgroup$
    – dbm
    Apr 25, 2013 at 15:35
  • $\begingroup$ @dbm I think you could and should update the question with this follow up problem. This way it will show top on the front page (of active questions) and come to everybody's attention. $\endgroup$
    – BoLe
    Apr 25, 2013 at 16:15

Your Answer

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

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