3

Consider a tube in 3D, where one of the dimensions is much flatter than the others:

pts = Table[{i, i, i/100.0}, {i, 1, 100}];
Graphics3D[Tube[pts]]

flat tube

This is fine, but a bit flat - now I want it an a square box.

Graphics3D[Tube[pts], BoxRatios -> 1]

bad tube

This has gone horribly wrong. How do I get a normal looking tube? Thanks

Michael E2
  • 235,386
  • 17
  • 334
  • 747
smörkex
  • 625
  • 4
  • 10
  • Related: https://mathematica.stackexchange.com/questions/101495/how-to-make-3-dimensional-arrows-look-good-when-their-lenghs-are-wildly-differen – smörkex Jul 18 '17 at 01:06
  • One solution I have come up with is to rescale the data points so they are of equal magnitude, and then to manually relabel the tick marks. However, this isn't really a solution – smörkex Jul 18 '17 at 03:42
  • 3
    I’m voting to close this question because you can't get a tube with a circular cross-section if the aspect ratio of your plot distorts circles. You will have to do some rescaling / reshaping by hand. – MarcoB Nov 27 '20 at 17:10

4 Answers4

3

Here's another way to interpret the task to get a cube-shaped box around the plot:

cubePR[plotrange_] := 
  plotrange /. {a_, b_} :> (a + b)/2 + #/2 {-1, 1} &[
   Max[Differences /@ plotrange]];

Show[#, PlotRange -> cubePR[PlotRange@#]] &@Graphics3D[Tube[pts]]

Michael E2
  • 235,386
  • 17
  • 334
  • 747
2

You can get a normal looking tube by giving it a reasonable radius (2nd argument to Tube).

pts = Table[{i, i, i/100}, {i, 1, 100}];
Graphics3D[Tube[pts, 5]]

tube

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
1

We can use Scale with parameters that depend on the BoxRatios and PlotRange to modify Tubes to look like circular independent of BoxRatios and PlotRange

ClearAll[scaledTube]
scaledTube[t_Tube, pr_, br_] := Scale[t, Normalize[-Subtract @@@ pr]/br, 
   Mean /@ CoordinateBounds[t[[1]]]]

Examples:

pts = Table[{i, i, i/100.0}, {i, 1, 100}];

tube = Graphics3D[Tube[pts, 5]]

enter image description here

With[{br = {1, 1, 1}, pr = {{1, 100}, {1, 100}, {0, 1}}}, 
 Labeled[Graphics3D[scaledTube[Tube[pts, 5], pr, br], 
   BoxRatios -> br, Axes -> True, PlotRange -> pr], 
  Grid[{{"box ratios: ", br}, {"plot range:", pr}}, 
   Alignment -> {Left, Center}], Top]]

enter image description here

versus what we get without scaling:

With[{br = {1, 1, 1}, pr = {{1, 100}, {1, 100}, {0, 1}}}, 
 Labeled[Graphics3D[Tube[pts, 5], BoxRatios -> br, Axes -> True,        
    PlotRange -> pr], 
  Grid[{{"box ratios: ", br}, {"plot range:", pr}}, 
   Alignment -> {Left, Center}], Top]]

enter image description here

With[{br = {1, 2, 3/2}, pr = {{1, 100}, {1, 100}, {0, 1}}}, 
 Labeled[Graphics3D[scaledTube[Tube[pts, 5], pr, br], 
   BoxRatios -> br, Axes -> True, PlotRange -> pr], 
  Grid[{{"box ratios: ", br}, {"plot range:", pr}}, 
   Alignment -> {Left, Center}], Top]]

enter image description here

versus no scaling:

enter image description here

If we replace Tube[pts, 5] with Tube[pts] in the first two examples above we get

enter image description here

and

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
1

We can use the option PlotRangePadding instead of BoxRatios to get a box with desired proportions without distorting Tubes:

Grid[Partition[#, 2] &[Labeled[
    Graphics3D[{Tube[pts]},  PlotRangePadding -> #, ImageSize -> 300], 
    Style[Row[{"PlotRangePadding -> ", #}], 14], Top] & /@ 
  {Automatic, 5 {1, 1, 3}, 5 {1, 1, 10}, {5, 5, 100}}], 
 Dividers -> All]

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896