How to make a tight crop of a 3d plot?

17

8

I like Mathematica, but it's syntax baffles me.

I am trying to figure out how to minimize the whitespace around a graphic.

For example,

ParametricPlot3D[{r Cos[t], r Sin[t], r^2}, {r, 0, 1}, {t, 0, 2 \[Pi]},
Boxed -> True, Axes -> False]


Puts the 3d bounding box at the limits of the view. But if I don't show the 3d bounding box,

ParametricPlot3D[{r Cos[t], r Sin[t], r^2}, {r, 0, 1}, {t, 0, 2 \[Pi]},
Boxed -> False, Axes -> False]


there is all this white space around the actual object.

Is there some way (syntax) that can put the view just around the visible objects?

Ok, from the below answers, I have two solutions; 1) use ImageCrop, or 2) use Method->{"ShrinkWrap" -> True}. However both of these options do a little something strange to the plot I want (maybe it is just a problem with the plot itself).

So the actual plot I am after is,

Module[{r = 1, \[Theta] = \[Pi]/2, \[CurlyPhi] = \[Pi]/6, \[Psi] = \[Pi]/12},
Framed@Show[
Graphics3D[
{
Arrow[{{0, 0, 0}, {1.1, 0, 0}}], Text["x", {1.2, 0, 0}],
Arrow[{{0, 0, 0}, {0, 1.1, 0}}], Text["y", {0, 1.2, 0}],
Arrow[{{0, 0, 0}, {0, 0, 1.1}}], Text["z", {0, 0, 1.2}],
Arrow[{{0, 0, 0}, r {Cos[\[Theta]] Sin[\[CurlyPhi]],
Sin[\[Theta]] Sin[\[CurlyPhi]], Cos[\[CurlyPhi]]}}]},
{Specularity[White, 50], Opacity[.1], Sphere[{0, 0, 0}, r]}
},
Boxed -> False,
ImageSize -> 600,
PlotRange -> 1.1 {{-r, r}, {-r, r}, {0, r}}
]]
]


Which has too much whitespace. If I replace Framed@Show[ with Framed@ImageCrop@Show[ I get,

which actually crops some of the (hemi)sphere. If just use Method -> {"ShrinkWrap" -> True}, in the Show options, I get,

which looks almost correct, but the x and z textboxes have now not included. Seems like I can't win!

3I believe I've found a small hack to get the ShrinkWrap option approach working: I placed white points with Opacity[0.01] just past each of my axis labels (or other text that's being cut-off). I'm running Mathematica 10.2. P.S. I don't have the 50 reputation points needed to post a response in the appropriate place above, but solving this was very useful to me and perhaps will be to others, so I'm posting it here. – jmc – 2015-08-03T20:57:04.727

4You've tried PlotRangePadding -> None and Method -> {"ShrinkWrap" -> True}? – J. M.'s ennui – 2012-09-11T02:36:46.173

Hi @J.M., PLotRangePadding-> None didn't seem to do much, but the Method option did (so thanks!). I'm curious though, how was I ever supposed to find this in the help? This is what I mean by not understanding Mathematica syntax. – ShaunH – 2012-09-11T03:00:41.933

@ShaunH You can find it here http://mathematica.stackexchange.com/q/809/193

– Dr. belisarius – 2012-09-11T03:21:15.197

@J.M. I think that one is good enough for an answer – Dr. belisarius – 2012-09-11T03:24:07.423

@J.M. I should stop answering questions. Where did you dig this up? – halirutan – 2012-09-11T03:46:20.243

@hal, I don't know which of you guys told me about this, but I'm sure it was one of you... – J. M.'s ennui – 2012-09-11T04:10:24.437

@bel, maybe you can edit it into your answer instead. :) – J. M.'s ennui – 2012-09-11T04:10:56.760

@Shaun, it is a bit infuriating that a fair amount of useful Mathematica functions are poorly documented, or not documented at all. That bit has been mentioned a number of times on this site; search around... – J. M.'s ennui – 2012-09-11T04:13:15.087

@J.M. Nah, post that and I'll delete my answer.That is what the OP wanted. If I only could remember all the jungle of functions and methods – Dr. belisarius – 2012-09-11T04:24:58.977

ImageCrop has a bug in some 8.0x versions when it comes to lightly coloured areas sometimes. Try something like imcrop[img_] := ImagePad[img, -BorderDimensions[img, 0]] instead. – Yves Klett – 2012-09-11T05:16:14.263

9

Actually, there isn't white space at all:

Show[RegionPlot3D[True, {x, -1, 1}, {y, -1, 1}, {z, 0, 1},
PlotStyle -> Directive[Yellow, Opacity[0.5]], Mesh -> None,
Boxed -> False, Axes -> False, PlotRangePadding -> 0],
ParametricPlot3D[{r Cos[t], r Sin[t], r^2}, {r, 0, 1}, {t, 0, 2 Pi} ]]


Edit

If you want to crop the image in 2D:

p = ParametricPlot3D[{r Cos[t], r Sin[t], r^2}, {r, 0, 1}, {t, 0, 2 Pi},
Boxed -> False, Axes -> False, PlotRangePadding -> 0];
Framed@ImageCrop@p


Edit

For your plot. Use .2 as Opacity. It has been reported elsewhere in this site that lowering the opacity too much makes other functions unable to detect the object.

Module[{r =
1, \[Theta] = \[Pi]/2, \[CurlyPhi] = \[Pi]/6, \[Psi] = \[Pi]/12},
Framed@ImageCrop@Show[
Graphics3D[
{{Specularity[White, 50], Opacity[.2],
Arrow[{{0, 0, 0}, {1.1, 0, 0}}], Text["x", {1.2, 0, 0}],
Arrow[{{0, 0, 0}, {0, 1.1, 0}}], Text["y", {0, 1.2, 0}],
Arrow[{{0, 0, 0}, {0, 0, 1.1}}], Text["z", {0, 0, 1.2}],
Arrow[{{0, 0, 0},
r {Cos[\[Theta]] Sin[\[CurlyPhi]],
Sin[\[Theta]] Sin[\[CurlyPhi]], Cos[\[CurlyPhi]]}}]}},
Boxed -> False, ImageSize -> 600,
PlotRange -> 1.1 {{-r, r}, {-r, r}, {0, r}}]]]


1Hi @belisarius, fine, it is not whitespace. But this doesn't answer the question of how to make a tight crop around just the object(s). – ShaunH – 2012-09-11T02:58:37.613

@ShaunH The crop IS tight, but in 3D. – Dr. belisarius – 2012-09-11T03:01:19.177

that definitely helps, but in the plot that I am after, it crops some of the object (see my edit to the question). – ShaunH – 2012-09-11T04:39:48.720

@ShaunH See edit – Dr. belisarius – 2012-09-11T04:47:55.633

haha, ok cool, so changing the opacity of the sphere fixes it. Why didn't I think of that! Cheers. – ShaunH – 2012-09-11T05:03:42.950

1The cropped half-sphere image still seems to be cut off by a few pixels on the lower border... – Yves Klett – 2012-09-11T07:51:05.153

I think this method rasterizes the vector graphics! right? – Hosein Rahnama – 2017-05-23T08:49:34.827

10

I think what you are looking for is ViewAngle option. The graph below compares default Automatic versus custom setting for ViewAngle. The image are framed intentionally to see clearly the removal of surrounding white space.

Framed[#, FrameMargins -> 0] & /@
(ParametricPlot3D[{r Cos[t], r Sin[t], r^2}, {r, 0, 1}, {t, 0, 2 \[Pi]},
Boxed -> False, Axes -> False, PlotRangePadding -> 0,
ImageSize -> 350 {1, 1}, ViewAngle -> #] & /@ {Automatic, .31})


Mathematica has rich set of options for so called "simulated camera" that "views" all 3D objects. To learn in detail about this i suggest downlading notebbok and watching free video of the @Yu-SungChang course Lights, Camera, Graphics! . Here is a illustrious diagram from that course explaining how ViewAngle option (measured in your example in 0.31 radians) sets up the view of a 3D objects.

You actually can change the ViewAngle setting interactively by holding CTRL or ALT key and dragging graphics with mouse - this effectively zooms in or out. See this tutorial for details.

You should point out, that this does not work automatically and that you have to adjust this for different viewing positions. But when I think about it: maybe the OP wasn't really interested in a Cropping->All solution and is fine to adjust it manually. 1+ – halirutan – 2012-09-11T03:26:14.007

2

ImageCrop seems to be a bit buggy (at least right here in Version 8.04, Win 64). It tends to crop lightly coloured areas rather agressively. You could try the following work-around, which works more reliably:

imcrop[img_] := ImagePad[img, -BorderDimensions[img, 0]]

g = Graphics3D[{Specularity[White, 50], Opacity[.1],
Sphere[{0, 0, 0}, 1]}, Boxed -> False,
PlotRange -> 1.1 {{-1, 1}, {-1, 1}, {0, 1}}
];
Column[Framed /@ {g, ImageCrop[g], imcrop[g]}]


For your graphics it seems to work without additional changes to Opacity or similar:

g = Module[{r =
1, \[Theta] = Pi/2, \[CurlyPhi] = Pi/6, \[Psi] = Pi/12},