12

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,
    ImagePadding -> 0,
    PlotRangePadding -> 0];
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}]

enter image description here

si-tacuisses
  • 123
  • 7

4 Answers4

14

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, 
 PlotRangePadding -> 0]

enter image description here

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]

enter image description here

Update: To wrap the matrix plot around the cylinder

Change the setting for TextureCoordinateFunction to

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

enter image description here

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]

enter image description here

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} &)]

enter image description here

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

kglr
  • 394,356
  • 18
  • 477
  • 896
  • Thanks this looks great exactly what I was looking for. Great Idea to use a parametric plot instead of Graphics Primitive. – si-tacuisses Dec 29 '12 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} &). –  Dec 29 '12 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] – si-tacuisses Dec 30 '12 at 00:27
  • @Rahul, right, thank you. Updated. – kglr Dec 30 '12 at 00:36
12

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[
           If[stack[[level, rad]] == 1,

            center = {Cos[interval*rad]/interval, 
               Sin[interval*rad]/interval, 0} // N;

            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} &],
        interval*rad, {0, 0, 1}, center]]

      , {rad, 1, width}]]
   ];

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:

enter image description here

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

amr
  • 5,487
  • 1
  • 22
  • 32
4

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]
  ]

pieces[n_, nrOfLayers_] := MapThread[
  layer[n, #, #2] &, {
    2 Pi Range[nrOfLayers]/n,
   Most@CellularAutomaton[30, RandomChoice[{0, 1}, n], nrOfLayers]
   }]

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

Example output: Example

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

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

Mathematica graphics

C. E.
  • 70,533
  • 6
  • 140
  • 264
3

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]]

CA on a cylinder

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]]

colorful sine on a cylinder

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574