How to make a cow smaller (in BubbleChart3D plot)
Here's a solution that can show 1000 cows using 1.45MB.
The idea is to project the 3D cow onto a 2D plane and then use this as the ChartElement
with Inset
. The advantage to using Inset
is the face will not rotate when rotating the graphic.
To project into 2D, I approximate the shape for the sake of speed and size of the mesh.
Options[approximateProjectedMeshRegion] = {RasterSize -> Automatic,
"NumPoints" -> Automatic, Method -> Automatic};
approximateProjectedMeshRegion[mr_, vp_, OptionsPattern[]] :=
Block[{n, num, rand, θ, bds, xd, yd, xmin, ymin, raw, im},
n = Replace[OptionValue[RasterSize], Except[_Integer?Positive] -> 90, {0}];
num = Replace[OptionValue["NumPoints"], Except[_Integer?Positive] -> 200000, {0}];
rand = RandomPoint[mr, num];
rand = RotationMatrix[{vp, {0, 0, 1}}].Transpose[rand];
θ = VectorAngle[(RotationMatrix[{vp, {0,0,1}}].{0,0,1})[[1;;2]], {0, 1}];
rand = Transpose[RotationMatrix[-θ].rand[[1;;2]]];
bds = MinMax /@ Transpose[rand];
{xd, yd} = Abs[Subtract @@@ bds]/n;
{xmin, ymin} = bds[[All, 1]];
raw = Transpose[{
Clip[n+1 - Round[Divide[#2 - ymin, yd]], {1, n}],
Clip[Round[Divide[#1 - xmin, xd]], {1, n}]
}& @@ Transpose[rand]
];
im = Image[SparseArray[Thread[Union[raw] -> 1]]];
ImageMesh[im, Method -> OptionValue[Method], DataRange -> bds]
]
The approximated cow:
bmr2D = approximateProjectedMeshRegion[cow, {1.3, -2.4, 2.}]
This is a poor looking approximation, but that's ok. With 1000 cows, you won't notice the jagged corners. Moreover, it's small in size:
facepts = MeshPrimitives[bmr2D, 2][[1, 1]];
ByteCount[Graphics3D[Inset[Graphics[Polygon[facepts]]]]]
1328
Now unfortunately BubbleChart3D
does not seem to accept Inset
inside ChartElements
, so we need to workaround. What we'll do is manually place the cows and use the options returned from BubbleChart3D
.
n = 1000;
chartopts = Options[BubbleChart3D[Thread[{
data[[1 ;; n, 1]], data[[1 ;; n, 2]], data[[1 ;; n, 3]], ConstantArray[0.1, n]}]
]];
scene = Graphics3D[
Inset[Graphics[Polygon[facepts]], #, Center, 15] & /@ data[[1 ;; n]],
chartopts,
ImageSize -> Large
];
Here's its size:
ByteCount[scene]
1458864
Compare this to the size of 1000 cow's from ExampleData
:
1000 ByteCount[ExampleData[{"Geometry3D", "Cow"}]]
1399072000
And here's the scene:
scene
And like I said earlier, if you rotate the graphic the cows will face the same direction: