# Applying an ArrayPlot as a texture to the surface of a cylinder

I would like to apply a matrix plot to the surface of a 3D cylinder. The matrix plot is the output from a custom cellular-automata, and it would be nice to see the lefthand side of the plot connected to the righthand side.

### Edit

This is the solution I ended up using:

mrt =
ArrayPlot[CellularAutomaton[30, RandomInteger[{0, 1}, 100], 30],
Frame -> False,
ParametricPlot3D[{Sin[t]/2Pi, Cos[t]/2Pi,u},{t,0,2Pi},{u,0,2},
Boxed -> False,
Axes -> False,
PerformanceGoal -> "Quality",
ImageSize -> {300, 300},
Lighting -> "Neutral",
PlotStyle -> Texture[mrt],
Mesh -> None,
ViewPoint -> {0, 3, 1}]

• I'm tempted to call this a duplicate of On coloring the faces of a surface differently with parameter-dependent colors because all the methods are covered there (except for how to draw a cylinder).
– Jens
Commented Dec 29, 2012 at 22:20
• As kguler has pointed out in the answer the principle of "Wrapping a rectangle to form a cylinder" has also been answered, sorry for the duplicate Commented Dec 29, 2012 at 23:20

You can use the raster image produced by MatrixPlot as Texture directive if you construct Cylinder using ParametricPlot3D or ContourPlot3D.

mplt = MatrixPlot[Table[Sin[x y/100], {x, -10, 10}, {y, -10, 10}],
ColorFunction -> "Rainbow", Frame -> False, ImagePadding -> 0,

### ParametricPlot3D

ParametricPlot3D[{Cos[theta], Sin[theta], rho}, {theta, -Pi, Pi}, {rho, 0, 2},
PlotStyle -> Directive[Specularity[White, 30], Texture[mplt]],
TextureCoordinateFunction -> ({#1, #3} &), Lighting -> "Neutral",
Mesh -> None, PlotRange -> All, TextureCoordinateScaling -> True]

Update: To wrap the matrix plot around the cylinder

Change the setting for TextureCoordinateFunction to

TextureCoordinateFunction -> ({#4, #5} &)  (*Thanks: @Rahul *)

Or leave out the TextureCoordinate... options out and use PlotStyle -> Texture[mplt] (thanks: @DROP TABLE):

ParametricPlot3D[{Cos[theta], Sin[theta], rho}, {theta, -Pi, Pi}, {rho, 0, 2},
PlotStyle -> Texture[mplt], Lighting -> "Neutral", Mesh -> None,
PlotRange -> All, ImageSize -> 400]

### ContourPlot3D

ContourPlot3D[x^2 + y^2 == 1, {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
Mesh -> None, Lighting -> "Neutral",
ContourStyle -> Directive[Specularity[White, 30], Texture[mplt]],
TextureCoordinateFunction -> ({#1, #3} &)]

### Related:

How to Texturize Disk/Circle/Rectangle

Heike's answer MathGroup: Texture on Disk in Mathematica 8

Wraping a Rectangle to Form a Cylinder

ColorFunction and ColorFunctionScaling Issue with ParametricPLot3D

• Thanks this looks great exactly what I was looking for. Great Idea to use a parametric plot instead of Graphics Primitive. Commented Dec 29, 2012 at 23:01
• It looks like you're projecting the texture on the $(x,z)$ coordinates, while I think the OP wants it to wrap around the cylinder along $(\theta,\rho)$. For the parametric plot, that would be TextureCoordinateFunction -> ({#4, #5} &).
– user484
Commented Dec 29, 2012 at 23:43
• The given answer by kguler did not exactly answer my question since the texture is duplicated, however the answer and the link to "Wraping a Rectangle to Form a Cylinder" have solved my problem. I ended up using: ParametricPlot3D[{Sin[t]/2 Pi, Cos[t]/2 Pi, u}, {t, 0, 2 Pi}, {u, 0, 2}, Axes -> False, ImageSize -> {300, 300}, Lighting -> "Neutral", PlotStyle -> Texture[mrt], Mesh -> None] Commented Dec 30, 2012 at 0:27
• @Rahul, right, thank you. Updated.
– kglr
Commented Dec 30, 2012 at 0:36

I made a program of this kind before and the most efficient solution I found was Cuboid. Or perhaps it was the best-looking solution. The rendering code is:

render[stack_, iterations_, color_, thickness_, overlap_] := Module[
{center, interval, width = Length[stack[[1]]]},
interval = 2. \[Pi]/width;

Last@Reap[Do[
Sow[Rotate[
Last@Reap[Do[

Sow[Cuboid[
center + {0, 0, -level} + {thickness, overlap/2 + .52, .52},
center + {0, 0, -level} - {0, overlap/2 + .52, .52}], color];
(*make the cylinder darker on the inside*)
Sow[Cuboid[
center + {0, 0, -level} + {0, overlap/2 + .52, .52},
center + {0, 0, -level} - {.02, overlap/2 + .52, .52}],
Darker[color, .5]]],
{level, 1, iterations}], _, {#1, #2} &],

];

It just goes through the matrix, and if there is a 1 it Sows the proper Cuboid. Note the Rotate, which rotates an entire column's worth of cells (columns are parameterized by rad).

The renderings look like:

By changing thickness you can also render the blocks as wafers to get a nice cylindrical look.

• Wow. This looks awesome! Commented Dec 30, 2012 at 10:44

I have an implementation of something like this. I might as well post it.

• The cylinder is made up of square polygons.
• coordinates lists all the corners of all the polygons at a certain height.
• layer takes the coordinates of the corners and generates the polygon required for one row in the cylinder.
• pieces generates all the rows.

Code:

coordinates[z_, n_, h_] := Riffle[
Append[z] /@ CirclePoints[n],
Append[z + h] /@ CirclePoints[n]
]

layer[n_, z_, data_] := GraphicsComplex[
coordinates[z, n, 2 Pi/n],
Polygon[# + {0, 1, 3, 2} /. {(2 n + 1) -> 1, (2 n + 2) -> 2}] & /@
Pick[Range[1, 2 n, 2], data, 1]
]

layer[n, #, #2] &, {
2 Pi Range[nrOfLayers]/n,
Most@CellularAutomaton[30, RandomChoice[{0, 1}, n], nrOfLayers]
}]

Graphics3D[
pieces[200, 50],
AspectRatio -> 1
]

Example output:

Different colors can be given for the inside and the outside:

Graphics3D[{
FaceForm[Blue, Yellow],
pieces[200, 50]
},
AspectRatio -> 1
]

• I think I recall a question along these lines in the last few days. Did that one end up getting closed as a duplicate of this one? Commented May 11, 2015 at 5:23
• @MarcoB not yet: 83112
– Kuba
Commented May 11, 2015 at 6:48
• @Kuba I suspect that might happen soon then ;-) This whole series of answers fits that question very closely. Commented May 11, 2015 at 6:53
• @MarcoB I think so, and +1 @ Pickett :)
– Kuba
Commented May 11, 2015 at 6:53

Instead of using ArrayPlot[], one might want to use Image[] directly to produce the textures. For instance, here is the CA texture:

BlockRandom[SeedRandom[42, Method -> "MersenneTwister"]; (* for reproducibility *)
ca30 = CellularAutomaton[30, RandomInteger[{0, 1}, 100], 30];]

(* Image[]'s convention is the reverse of ArrayPlot[]'s *)
tex = Image[1 - ca30, ImageSize -> Large];

ParametricPlot3D[{2 Cos[u], 2 Sin[u], z}, {u, -π, π}, {z, 0, 2},
Axes -> None, Boxed -> False, Lighting -> "Neutral",
Mesh -> None, PlotStyle -> Texture[tex]]

Here's a colorful example:

tex2 = Colorize[Image[Rescale[
N[Table[Sin[π x/10 + Sin[π y/10]], {x, 0, 20}, {y, 0, 40}]]], ImageSize -> Large],
ColorFunction -> "Rainbow"];

ParametricPlot3D[{Cos[u], Sin[u], z}, {u, -π, π}, {z, 0, 2},
Axes -> None, Boxed -> False, Lighting -> "Neutral",
Mesh -> None, PlotStyle -> Texture[tex2]]