3
$\begingroup$

Seeking advice for how to construct an oblique chart plot of {x,y} and {x,z} value lists in a 3D View where the viewer can trace a line from {x,y,0} to {x,0,0}, and then jump to the associated {x,0,z} value.

Idea here is to present two related variables sharing a common x-value on one graphic.

In the following sample code of 10 points (although I typically have to present hundreds of points), I have two (possibly 3) issues in my code:

  1. {x,0,z} points are correctly connected via the line to their corresponding {x,0,0} point. How do I specify the same for the {x,y,0} points so that they match up with their corresponding {x,0,0} point?

  2. How do I eliminate the bounding 3D Box view?

  3. Am I completely headed in the wrong direction (e.g., I should generate 2D ListPointPlots and then "marry" them at the X-Axis by projecting each as the inside face of a 3D cube)?

values[{x, z}] = Table[{i, 0, RandomInteger[{10, 15}]}, {i, 0, 10}];
values[{x, y}] = Table[{i, RandomInteger[{1, 10}], 0}, {i, 0, 10}];
ListPointPlot3D[{values[{x, z}], values[{x, y}]}
 , Filling -> Axis
 , AxesLabel -> {"X-Axis", "Y-Axis", "Z-Axis"}
 , ViewPoint -> {0, 2, 2.75}
 , ViewVertical -> {0, 1, 0.04}]

Attached is a reference example for an Oblique data chart of two variables relative to a common X-Value.

Oblique Chart of Systolic and Diastolic Blood Pressure

$\endgroup$

3 Answers 3

4
$\begingroup$

For a start:

valxz = Table[{i, 0, RandomInteger[{10, 15}]}, {i, 0, 10}];
valxy = Table[{i, RandomInteger[{1, 10}], 0}, {i, 0, 10}];
Graphics3D[{PointSize[0.03],
  Point[valxy], Point[valxz], Thickness[0.01],
  Line[{{{1, 0, 0} #, #}}] & /@ valxy, 
  Line[{{{1, 0, 0} #, #}}] & /@ valxz
  }, Axes -> True, Boxed -> False, AxesOrigin -> {0, 0, 0}, 
 AxesLabel -> {"X", "Y", "Z"}]

enter image description here

You may beatify it using e.g. Color, Style e.t.c.

$\endgroup$
3
  • $\begingroup$ Oh -- this is GREAT!!! THANK YOU!!!! $\endgroup$ Oct 11, 2021 at 16:37
  • $\begingroup$ Did you mean beatify or beautify? I suspect the latter, but like the former rather more! $\endgroup$ Oct 11, 2021 at 17:58
  • 1
    $\begingroup$ Well, I suppose it is nor good enough for the former. $\endgroup$ Oct 11, 2021 at 19:02
3
$\begingroup$

An alternative using Tube

Clear["Global`*"]

SeedRandom[1234];

values[{x, z}] = Table[{i, 0, RandomInteger[{10, 15}]}, {i, 0, 10}];
values[{x, y}] = Table[{i, RandomInteger[{1, 10}], 0}, {i, 0, 10}];

Graphics3D[{
  CapForm["Square"],
  Tube[{ReplacePart[#, 3 -> 0], #}, 1/4] & /@ values[{x, z}],
  Tube[{ReplacePart[#, 2 -> 0], #}, 1/4] & /@ values[{x, y}]},
 Axes -> True,
 AxesLabel -> {"X-Axis", "Y-Axis", "Z-Axis"},
 ViewPoint -> {1, 1.7, 2.75},
 ViewVertical -> {0, 1, 0.04},
 Boxed -> False,
 AxesEdge -> {Automatic, {1, -1}, {1, -1}}]

enter image description here

$\endgroup$
1
  • $\begingroup$ Bob -- THANK YOU -- that is fantastic as well! $\endgroup$ Oct 12, 2021 at 1:39
3
$\begingroup$
SeedRandom[1];
systolic = ReverseSort /@ RandomInteger[{70, 180}, {24, 2}];
diastolic = ReverseSort /@ RandomInteger[{40, 120}, {24, 2}];

We can use PairedBarChart and post-process the output to get a 3D look as in the example in OP:

barspacing = {0, 2, 0};

pbc = PairedBarChart[systolic, diastolic, 
   BarOrigin -> "XAxis", 
   BarSpacing -> barspacing, 
   PlotRangePadding -> {{0, 2}, {Automatic, Automatic}},
   PerformanceGoal -> "Speed", 
   ImagePadding -> 50,
   ImageSize -> Large, 
   ChartStyle -> {Directive[EdgeForm[{Opacity[1], Black}], Black, HatchFilling[Pi/4, 1]],
    Directive[EdgeForm[{Opacity[1], Black}], GrayLevel[.7]]}, 
  Epilog -> {Text[Style["systolic", 14], 
       {-2 (3 + barspacing[[2]]), 75}, {Center, Bottom}, {0, 1}],
    Text[Style["diastolic", 14], 
       {-2 (3 + barspacing[[2]]), -75}, {Center, Top}, {0, -1}], 
    Line[{{0, 70}, {1 + (2 + barspacing[[2]]) Length @ systolic , 70}}],
    Text[Style[70, 14], Offset[{5, 0},
       {1 + (2 + barspacing[[2]]) Length @ systolic, 70}], {Left, Center}], 
    Line[{{0, -40}, {1 + (2 + barspacing[[2]]) Length @ systolic, -40}}], 
    Text[Style[40, 14], Offset[{5, 0}, 
       {1 + (2 + barspacing[[2]]) Length@systolic , -40}], {Left, Center}]}]

enter image description here

Use ShearingTransform to modify the rectangle, line and text primitives in the lower panel:

pbc /. rlt : (_Rectangle | _Line | _Text ) /; Not[FreeQ[rlt, {_, _?Negative}]] :> 
    GeometricTransformation[rlt, ShearingTransform[3 Degree, {1, 0}, {0, 1}]] 

enter image description here

An alternative approach using the option ChartElementFunction:

st = ShearingTransform[5 Degree, {1, 0}, {0, 1}];

bs = 1;
pbc1 = PairedBarChart[systolic -> ChartElementData["Rectangle"], 
  diastolic -> (GeometricTransformation[ChartElementData["Rectangle"][##], st] &),
 Axes -> False,
 BarSpacing -> {0, bs, 0}, 
 BarOrigin -> "XAxis", 
 ImageSize -> 800, 
 ChartElementFunction -> (#3[[1]][##] &)]

enter image description here

We can construct the axes using AxisObject:

axes = AxisObject[Line[{{0, 0}, #}], {0, #2}, 
     AxisLabel -> Placed[Style[#3, 16], {0.5, {0.5, -1.25}}], 
     RotateLabel -> #4 Degree , 
     TickDirection -> "Outward", 
     TickLabelPositioning -> "Tip", 
     AxisStyle -> FontSize -> 16] & @@@ 
  {{st[{0, -Max @ diastolic}], Max@diastolic, "diastolic", 55 }, 
   {{0, Max @ systolic}, Max @ systolic, "systolic", 90 }};

and add axes and other annotations using the option Epilog:

Show[pbc1, 
 Epilog -> {axes, 
   Line[{{0, 70}, {(2 + bs) Length @ systolic, 70}}], 
   Text[Style[70, 16], {1 + (2 + bs) Length @ systolic, 70}, {-1, 0}], 
   Line[st /@ {{0, -40}, {(2 + bs) Length @ systolic, -40}}], 
   Text[Style[40, 16], st @ {1 + (2 + bs) Length @ systolic, -40}, {-1, 0}]}, 
 ImagePadding -> 60]

enter image description here

$\endgroup$
1
  • 1
    $\begingroup$ WOW! THIS is true to the original example! I know there are so many ways to generate plots in Mathematica, but this blows me away having one question and three distinctly different answers -- all of which are GREAT! Thank you! $\endgroup$ Oct 12, 2021 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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