5
$\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$ Commented 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$ Commented Dec 16, 2020 at 22:46
  • $\begingroup$ Thank you @Carl; great points. $\endgroup$ Commented Dec 16, 2020 at 22:49
1
$\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$
1
  • $\begingroup$ I'm trying to use Overlay to place something at an exact point in terms of graph coordinates. Do you know of a way to compute the "image coordinates" of a point in terms of "graph coordinates"? $\endgroup$ Commented Jun 22 at 4:25

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.