4
$\begingroup$

I have been trying to modify a clipped graph by adding a text a label outside the frame, with no success so far.

Code for contour per request to get the rest of the code to run:

    ClearAll[Sbase, Vbase, Zbase, countour];
    Sbase = 50 10^3;
    Vbase = 240;
    Zbase = Vbase^2/Sbase;
    countour[M_, Zpu_, XR_] := 
        Circle[{M/Z Cos[\[Phi]], -M/Z Sin[\[Phi]]}, 1/Z] /. {Z -> Zpu Zbase, \[Phi] -> ArcTan[XR]}

This is my graph:



g1 = Graphics[
   Flatten[
    {Red,
     Table[countour[M, 0.02, 3], {M, 0.98, 1.02, 0.001}],
     Blue,
     Table[countour[M, 0.04, 1], {M, 0.98, 1.02, 0.001}]
     }
    ],
   Axes -> True, PlotRangeClipping -> True, AxesStyle -> Thick, 
   AxesLabel -> {x, y}, ImagePadding -> {{All, 50}, {All, All}}, 
   Frame -> True, PlotRange -> {{-0.3, 0.3}, {-0.3, 0.3}}];

The contour function just produces circles with differing centers and radii. I am zooming in close to the origin and clipping everything else to get this:

Frame with clipping

All is fine up to now, but I also want to add text labels outside the clipped frame. My successful trials, along with what I see suggested online(including StackExchange), hinge on setting PlotRangeClipping to False, for example as suggested here: "insert a text outside the frame".

That does not work for me, because when I try it I get:

ClearAll[g1, addLabel];
addLabel = Show[#,
    Epilog -> Text[#2, Scaled[{1.02, 0.7}], {-1, -1}],
    PlotRangeClipping -> False, 
    ImagePadding -> {{All, 50}, {All, All}}] &;
g1 = Graphics[
   Flatten[
    {Red,
     Table[countour[M, 0.02, 3], {M, 0.98, 1.02, 0.001}],
     Blue,
     Table[countour[M, 0.04, 1], {M, 0.98, 1.02, 0.001}]
     }
    ],
   Axes -> True, AxesStyle -> Thick, AxesLabel -> {x, y}, 
   Frame -> True, PlotRange -> {{-0.3, 0.3}, {-0.3, 0.3}}];
addLabel[g1, Style["M\[Equal]1", 16, Red]]

enter image description here

Which is not what I want at all. If I try to keep PlotRangeClipping as 'True` I lose the text label.

Any recommended workarounds ?

$\endgroup$
0

3 Answers 3

2
$\begingroup$

First, create a graphics object with your primitives, using the desired plot range, with clipping and no image padding:

g1 = Graphics[
    Flatten[{
        Red,
        Table[countour[M,0.02,3],{M,0.98,1.02,0.001}],
        Blue,
        Table[countour[M,0.04,1],{M,0.98,1.02,0.001}]
    }],
    PlotRangeClipping->True,
    ImagePadding->0,
    PlotRange->{{-0.3,0.3},{-0.3,0.3}}
];

Then, inset this graphics object into your graphic, along with the text labels and your overall axes/frame specifications:

Graphics[
    {
    Inset[g1, {0, 0}, {0, 0}, {.6, .6}],
    Text[Style["M\[Equal]1",16,Red],Scaled[{1.02,0.7}],{-1,-1}]
    },
    PlotRange -> {{-.3, .3}, {-.3, .3}},
    ImagePadding -> {{Automatic, 50}, {Automatic, Automatic}},
    Frame -> True,
    Axes -> True,
    AxesLabel -> {x,y},
    AxesStyle -> Thick
]

enter image description here

$\endgroup$
1
  • $\begingroup$ Yes, Thank you ! This worked exactly what I wanted. $\endgroup$ Dec 16, 2020 at 20:38
2
$\begingroup$

You can also clip the graphics primitives:

ClearAll[clip]
clip[prange_] := RegionIntersection[Rectangle @@ Transpose[prange], #] /. _EmptyRegion -> {} &;

Wrap your countour[...]s with clip[plotrange]

plotrange = {{-0.3, 0.3}, {-0.3, 0.3}};

g2 = Graphics[Flatten[{Red, 
     Table[clip[plotrange] @ countour[M, 0.02, 3], {M, 0.98, 1.02, 0.001}], 
     Blue, Table[clip[plotrange] @ countour[M, 0.04, 1], {M, 0.98, 1.02, 0.001}]}], 
   Axes -> True, AxesStyle -> Thick, 
   AxesLabel -> {x, y}, Frame -> True, PlotRange -> plotrange];

addLabel[g2, Style["M\[Equal]1", 16, Red]]

enter image description here

Caveat: This approach does not work with primitives like FilledCurve, BezierCurve, BSPlineCurve, and transformed primitives (e.g. primitives wrapped inside GeometricTransformation, Translate, Rotate, Scale etc.) which do not work with RegionIntersection.

$\endgroup$
2
  • $\begingroup$ This approach won't work for things like BSplineCurve, FilledCurve, etc. Not every graphics primitive is also a region primitive. $\endgroup$
    – Carl Woll
    Dec 16, 2020 at 22:46
  • $\begingroup$ Thank you @Carl; great points. $\endgroup$
    – kglr
    Dec 16, 2020 at 22:49
0
$\begingroup$

I'm a little late to the party, but I find any time I'm forced to deal with PlotRangeClipping and ImagePadding things start to get janky. My preferred way of doing this via the Overlay[] function.

It's lightweight, fairly intuitive, and doesn't require moving all the labels out of your current plot.

(*Your Plot*)
ClearAll[Sbase, Vbase, Zbase, contour];

Sbase = 50 10^3;
Vbase = 240;
Zbase = Vbase^2/Sbase;
countour[M_, Zpu_, XR_] := 
 Circle[{M/Z Cos[\[Phi]], -M/Z Sin[\[Phi]]}, 
   1/Z] /. {Z -> Zpu Zbase, \[Phi] -> ArcTan[XR]}

g1 = Graphics[Flatten[{
     Red, Table[countour[M, 0.02, 3], {M, 0.98, 1.02, 0.001}],
     Blue, Table[countour[M, 0.04, 1], {M, 0.98, 1.02, 0.001}]
     }],
   Axes -> True,
   PlotRangeClipping -> True,
   AxesStyle -> Thick,
   AxesLabel -> {x, y},
   ImagePadding -> {{All, 50}, {All, All}},
   Frame -> True,
   PlotRange -> {{-0.3, 0.3}, {-0.3, 0.3}}];

(*My Overlay*)
Overlay[{
  g1,
  Style["M=1", Red, FontSize -> 20, FontFamily -> "Times"]},
 Alignment -> {0.95, 0.4}]

Which produces the following.

enter image description here

Alignment isn't explained super well in the Overlay documentation, so for those that need it:

Alignment->{-1,-1} is bottom left,

Alignment->{1,1} is top right,

Alignment->{0,0} is in the middle (not of the graph, but the entire graphic/plot).

$\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.