3
$\begingroup$

As stated in the Mathematica documentation,

PointSize[d] is a graphics directive which specifies that points which follow are to be shown if possible as circular regions with diameter d. The diameter d is given as a fraction of the total width of the plot.

On the other hand,

Scaled[{dx,dy,...},{x_0,y_0,...}] gives a position obtained by starting at ordinary coordinates x_0,y_0,..., then moving by a scaled offset {dx,dy,...}.

In this case, the scaled offsets are specified as a fraction of each plot direction.

This leads to an apparent incompatibility in combining circular objects whose sizes are determined by the width of the plot (and because they are circular, their extent along the vertical direction is also specified by the width of the plot) and objects with vertical offsets which are determined by the height of the plot -- how can this be reconciled?

As an example, if I apply a horizontal offset, the offset objects are positioned as expected (on the boundary of the points), regardless of the specified plot range:

sites = Flatten[Table[{i, j}, {i, 0, 3}, {j, 0, 1}], 1];
psize = 0.12;
offset = psize/2;

Graphics[{PointSize[psize], Map[Point[#] &, sites], PointSize[0.2 psize], 
          Red, Map[Point[Scaled[{offset, 0}, #]] &, sites]}, 
          PlotRange -> Automatic, Frame -> True]
Graphics[{PointSize[psize], Map[Point[#] &, sites], PointSize[0.2 psize], 
          Red, Map[Point[Scaled[{offset, 0}, #]] &, sites]},
          PlotRange -> {{-1, 4}, Automatic}, Frame -> True]

enter image description here enter image description here

If I try the same with a vertical offset, however, the offsets do not remain fixed since the point size is changing as the width of the plot is adjusted:

Graphics[{PointSize[psize], Map[Point[#] &, sites], PointSize[0.2 psize], 
          Red, Map[Point[Scaled[{0, offset}, #]] &, sites]}, 
          PlotRange -> Automatic, Frame -> True]
Graphics[{PointSize[psize], Map[Point[#] &, sites], PointSize[0.2 psize], 
          Red, Map[Point[Scaled[{0, offset}, #]] &, sites]},
          PlotRange -> {{-1, 4}, Automatic}, Frame -> True]

enter image description here enter image description here

Is there way to specify a vertical offset based on the width of the plot, or some other way to resolve this issue?

Lastly, I am using Point rather than Disk because of flattening that occurs do to scaling, as discussed in this question. So any solution that needs to replace Point with Disk would preferably have a way of resolving the flattening issue, as well.

Thank you!

$\endgroup$
2
  • $\begingroup$ You could use AspectRatio ->1 but that would distort the axis scales, which is probably not something you want... $\endgroup$
    – Jens
    Jun 27, 2018 at 17:22
  • $\begingroup$ @Jens Yeah, that wouldn't be an ideal solution, as it does cause various problematic distortions. Thanks for the response, though. $\endgroup$ Jun 27, 2018 at 21:03

2 Answers 2

1
$\begingroup$

If you know in advance that the option value for AspectRatio is, say, ar you can simply use offset / ar for the vertical offset. If not, you can post-process the Graphics output to extract the AspectRatio and make the necessary change in Scaled coordinates using ReplaceAll:

ClearAll[aRatio, adjustScaled]
aRatio =  AspectRatio /. AbsoluteOptions[#, AspectRatio] &;
adjustScaled = # /. Scaled[a_, b___] :> Scaled[{1, 1 / aRatio[#]} a, b] &;

Examples:

sites = Flatten[Table[{i, j}, {i, 0, 3}, {j, 0, 1}], 1];
psize = 0.12;
offset = psize/2;

g3 = Graphics[{PointSize[psize], Map[Point[#] &, sites], 
    PointSize[0.2 psize], Red, Map[Point[Scaled[{0, offset}, #]] &, sites]}, 
   PlotRange -> Automatic, Frame -> True];
g4 = Graphics[{PointSize[psize], Map[Point[#] &, sites], 
    PointSize[0.2 psize], Red, Map[Point[Scaled[{0, offset}, #]] &, sites]}, 
   PlotRange -> {{-1, 4}, Automatic}, Frame -> True];
g5 = Show[g3, AspectRatio -> 1/2, PlotRange -> {{-2, 5}, {-1, 2}}];

Row[{g3, adjustScaled @ g3}, Spacer[10]] // Style[#, ImageSizeMultipliers -> {1, 1}] &

enter image description here

Row[{g4, adjustScaled @ g3}, Spacer[10]] // Style[#, ImageSizeMultipliers -> {1, 1}] &

enter image description here

Row[{g5, adjustScaled @ g3}, Spacer[10]] // Style[#, ImageSizeMultipliers -> {1, 1}] &

enter image description here

The point sizes scale with the image size:

ag4 = adjustScaled @ g4;
frames = Table[Pane[Show[ag4, ImageSize -> s], 
   ImageSize -> {500, 300}, Alignment -> Center], 
  {s, Join @@ {#, Reverse @ Most @ #} & @ Range[100, 500, 10]}];
Export["g4.gif", frames]

enter image description here

$\endgroup$
1
  • $\begingroup$ Thanks for the solution! I will have to test this out in non-contrived situations to get a sense of the performance hit, but it does exactly what I want. $\endgroup$ Jul 24, 2018 at 4:39
0
$\begingroup$

Instead of trying to use PointSize and Scaled, why not use AbsolutePointSize and Offset? For example (note that I tweaked your code slightly to use Tuples to generate the sites and a single Point object where possible):

sites = Tuples[{Range[0,3], Range[0,1]}];
psize = 40;
offset = psize/2;

Graphics[
    {
    AbsolutePointSize[psize], Point[sites],
    AbsolutePointSize[.2 psize], Red, Point[Thread[Offset[{offset,0}, sites], List, -1]]
    },
    PlotRange->Automatic,
    Frame->True
]

Graphics[
    {
    AbsolutePointSize[psize], Point[sites],
    AbsolutePointSize[.2 psize], Red, Point[Thread[Offset[{0, offset}, sites], List, -1]]
    },
    PlotRange->Automatic,
    Frame->True
]

enter image description here

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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