Wolfram Research

Function Repository Resource:

RiemannSurfacePlot3D

Source Notebook

Plot Riemann surfaces of compositions of elementary functions

Contributed by: Michael Trott

ResourceFunction["RiemannSurfacePlot3D"][wf(z), reim(z), {z, w}]

generates a three-dimensional plot of the Riemann surface of w over the complex z-plane with reim(z) equal to Re(z) or Im(z).

ResourceFunction["RiemannSurfacePlot3D"][wf(z), {ζ1,ζ2,ζ3},{z,w}]

generates a three-dimensional plot of the Riemann surface of w in ζ1,ζ2,ζ3-space. ζi can be any linear combination of Re[z],Im[z],Re[w], Im[w].

ResourceFunction["RiemannSurfacePlot3D"][p(z,w),reim(z),{z, w}]

generates a three-dimensional plot of the Riemann surface of w defined through the equality p(z,w) over the complex z-plane.

ResourceFunction["RiemannSurfacePlot3D"][p(z,w),{φx,y,φx,u,φx,v,φy,u,φy,v,φu,v},{z, w}]

generates a three-dimensional plot of the Riemann surface of w defined through the equality p(z,w) as a complex functions represented in 2≃ℝ4 (x=Re(z),y=Im(z),u=Re(w),v=Im(w)) rotated by the angles φx,y,φx,u,φx,v,φy,u,φy,v,φu,v displayed as the first three components of the rotated points.

Details and Options

The function allows to plot Riemann surfaces of compositions of elementary functions with a finite number of branch points; one branch point can be at .
The resulting plots are always centered at the origin and all finite branch points are included in the horizontal plot range.
For branch points with finite ramification index all sheets are included, for logarithmic branch points three sheets are included by default.
RiemannSurfacePlot3D has the same options as Graphics3D, with the following additions:
PlotStyle Automatic graphics directives for the style for the complete surface or the patches making up the surface
ColorFunction Automatic how to determine the color of surfaces
"ShowBranchPoints" False if branch points positions should be indicated as thin vertical tubes with tootips
"BranchPointStyle" Automatic how to draw the vertical tubes at branch points
"BranchPointOffset" 10-6 offset from the branch points to start numerical computations
"BranchPointPlotRangeFactor" 1.5 radial plot range factor with respect to the furthest branch point
"LogSheets" {-1, 0, 1} list of sheets to use for logarithmic branch points with respect to the principal sheet
PlotPoints {60, 30} approximate azimuthal and radial plot points
"StitchPatches" False if neighboring patches should be stitched together
WorkingPrecision 25 precision to use in numerical computations
With ColorFunctionfunc, the arguments supplied to func are z and w (both asumed to be complex numbers). No scaling is applied to z and w.
Stitching the surface patches together results in watertight surfaces, better suited for 3D printing.
Additionally, all options of Graphics3D can be specified in ResourceFunction["RiemannSurfacePlot3D"].
The patches of the surface are computed through numerically solving differential equations.
The last solution of the differential equations is cached for a given w=f(z). As a result varying the second argument is fast and interactive exploration is possible.

Examples

Basic Examples

The Riemann surface of the square root functions plotted as the real part of :

In[1]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[z], Re[w], {z, w}]
Out[1]=

The Riemann surface of the cube root functions plotted as the real part of :

In[2]:=
ResourceFunction["RiemannSurfacePlot3D"][w == z^(1/3), Re[w], {z, w}]
Out[2]=

The Riemann surface of the function w defined implicitly through w5=1-z3:

In[3]:=
ResourceFunction["RiemannSurfacePlot3D"][w^5 == 1 - z^3, Re[w] + Im[w], {z, w}]
Out[3]=

The Riemann surface of a function with three logarithmic branch points at z=1, z=-(-1)1/3, and z=-(-1)2/3:

In[4]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Log[1 - z^3], Im[w], {z, w}]
Out[4]=

The Riemann surface of a more complicated function with multiple logarithmic branch points:

In[5]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Log[z/(Log[z - 1] - Log[z + 1])], Im[w], {z, w}]
Out[5]=

Scope

The (vertical) function value displayed can be any linear combination of Re[z], Im[z], Re[w], Im[w]:

In[6]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Sqrt[z^2 + 1] + Sqrt[z - 1], Re[w] + 2 Im[w] - Re[z]/5, {z, w}, ViewPoint -> {-3.08, -1.41, -0.0}]
Out[6]=

The {x,y,z}-values displayed can be any linear combination of Re[z], Im[z], Re[w], Im[w]:

In[7]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Sqrt[z^2 - I] + Sqrt[z - 1], {Re[z] + Im[w], Im[z] + Re[w], Re[w] + Im[w] - Re[z]}, {z, w}]
Out[7]=

A wide class of compositions of elementary functions can be visualized. Here are some examples containing trigonometric and inverse trigonometric functions:

In[8]:=
ResourceFunction["RiemannSurfacePlot3D"][w == ArcSin[1 + Sqrt[z]], Im[w], {z, w}]
Out[8]=
In[9]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Cos[Tan[Log[z]] + z], Re[w], {z, w}]
Out[9]=
In[10]:=
ResourceFunction["RiemannSurfacePlot3D"][w == ArcCos[Log[-(z^2/2)]], Im[w], {z, w}]
Out[10]=

Riemann surface of nested square and cube roots:

In[11]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Sqrt[Power[z, (3)^-1] + z], Re[w], {z, w}]
Out[11]=
In[12]:=
ResourceFunction["RiemannSurfacePlot3D"][w == z^Sqrt[z], Im[w], {z, w}]
Out[12]=

Root objects define implicitly bivariate polynomials and the corresponding Riemann surface can be plotted. Here is an irreducible quantic shown:

In[13]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Root[1 - z^2 + 2 z #^2 + #^5 &, 1], Im[w], {z, w}]
Out[13]=

For the purpose of the RiemannSurfacePlot3D function, the product log function is considered an elementary function:

In[14]:=
ResourceFunction["RiemannSurfacePlot3D"][w == ProductLog[z (z - 1) ], Re[w], {z, w}]
Out[14]=

Here are the real and imaginary parts of the function :

In[15]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[I - Log[z]], Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[I - Log[z]], Im[w], {z, w}]}
Out[15]=

The vertical value of the surface can be a linear combination of the real and imaginary parts of z and w:

In[16]:=
Table[ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[I - Log[z]], RandomReal[{-1, 1}, 4].{Re[z], Im[z], Re[w], Im[w]}, {z, w}], {4}]
Out[16]=

Even all three coordinate values of the surface can be such a linear combination:

In[17]:=
Table[ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[I - Log[z]], Table[RandomReal[{-1, 1}, 4].{Re[z], Im[z], Re[w], Im[w]}, 3], {z, w}], {4}]
Out[17]=

Options

PlotStyle

Specify a plot style for the whole Riemann surface:

In[18]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Power[1 - z^3, (3)^-1], Re[w], {z, w}, PlotStyle -> Directive[GrayLevel[0.5], Specularity[Yellow, 20]]]
Out[18]=

A list of style directives will be applied cyclically to the radial-azimuthal patches that result from the branch point-induced tensor-product subdivision of the complex z-plane:

In[19]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Power[1 - z^3, (3)^-1], Re[w], {z, w}, PlotStyle -> Table[Directive[Opacity[0.5], RandomColor[]], {25}]]
Out[19]=

ColorFunction

Color the surface according to the argument of w:

In[20]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[Log[z + z^3]], Im[w], {z, w}, ColorFunction -> (Directive[Opacity[0.8], Hue[(Arg[#2] + Pi)/(2 Pi)]] &)]
Out[20]=

Use a color functions that depends on z+w:

In[21]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[z/Log[z]], Im[w], {z, w}, ColorFunction -> (Directive[Opacity[0.5], ColorData["GreenPinkTones"][(ArcTan[Abs[#1] + Abs[#2]] + 1)/
       2]] &)]
Out[21]=

Color a Riemann surface according to the distance to the nearest branch point, with parts of the surface that are near to a branch point being red:

In[22]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Power[1 - z^4, (4)^-1], Im[w], {z, w}, ColorFunction -> (Directive[Opacity[0.9], ColorData["TemperatureMap"][
      1 - Min[Function[bc, Abs[#1 - bc]] /@ {1, -1, I, -I}]^2]] &)]
Out[22]=

ShowBranchPoints and BranchPointStyle

With the setting "ShowBranchPoints"True, branch points over the z-plane will be indicated as vertical tubes (mouseover the vertical tubes to see z-positions of the branch points):

In[23]:=
ResourceFunction["RiemannSurfacePlot3D"][w == ArcSin[z], Re[w], {z, w}, "ShowBranchPoints" -> True]
Out[23]=

The option "BranchPointStyle" determines the color of these tubes:

In[24]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Sqrt[z - 1] + Sqrt[z + 1] - 2 Sqrt[z^2 + I], Re[w], {z, w}, PlotStyle -> Directive[Opacity[0.5], Yellow], "ShowBranchPoints" -> True, "BranchPointStyle" -> Blue]
Out[24]=

BranchPointPlotRangeFactor

The default plot range extends the distance from the origin to the furthest branch point by 50%:

In[25]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Log[z] (1 - z^2)^(1/3), Im[w], {z, w}, "ShowBranchPoints" -> True]
Out[25]=

Show the Riemann surface with more padding (but same box ratios):

In[26]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Log[z] (1 - z^2)^(1/3), Im[w], {z, w}, "ShowBranchPoints" -> True, "BranchPointPlotRangeFactor" -> 3]
Out[26]=

LogSheets

Logarithmic branch points connect infinitely many sheets. By default, the principal sheet and one sheet below and above are used. Using the option "LogSheets" more or less sheets could be displayed:

In[27]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == -Log[z], Re[w] + Im[w], {z, w}, ViewPoint -> {1.1, -2.15, 0.6}],
 ResourceFunction["RiemannSurfacePlot3D"][w == -Log[z], Re[w] + Im[w], {z, w}, "LogSheets" -> {-2, -1, 0, 1, 2}, ViewPoint -> {1.1, -2.15, 0.6}]}
Out[27]=

BranchPointOffset

The default the numerical computation of the surface patches starts 10-6 away from any branch point. For most surfaces this results in defacto invisible gaps between the patches:

In[28]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Root[1 - z^2 + 2 z #^2 + #^5 &, 1], Im[w], {z, w}]
Out[28]=

By specifying a larger offset from the branch point-generated patches gaps between the patches become visible. The next input colors the patches differently:

In[29]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Root[1 - z^2 + 2 z #^2 + #^5 &, 1], Im[w], {z, w},
 "BranchPointOffset" -> 0.08, PlotStyle -> Table[Directive[Opacity[RandomReal[{0.8, 0.9}]], GrayLevel[0.7], Specularity[ColorData["TemperatureMap"][RandomReal[]], 20]], {100}]]
Out[29]=

PlotPoints

The option PlotPoints determines the approximate number of radial and azimuthal plot points:

In[30]:=
Table[ResourceFunction["RiemannSurfacePlot3D"][w == z^(1/3), Im[w], {z, w}, PlotPoints -> j {3, 6}, PlotLabel -> (PlotPoints -> j {4, 8}), PlotStyle -> Directive[Opacity[0.6], EdgeForm[{Thickness[0.001], Black}]]], {j, 4}]
Out[30]=

StitchPatches

The option "StitchPatches" tries to connect neighboring patches by stitching them together with tiny polygons to obtain water-tight surfaces:

In[31]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == (z^2 + z^6)^(1/6), Im[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][w == (z^2 + z^6)^(1/6), Im[w], {z, w}, "StitchPatches" -> True]}
Out[31]=

While visually the two graphics are quite similar, the stitched patches result in a larger number of graphics complexes in the resulting 3D graphic:

In[32]:=
Count[#, _GraphicsComplex, {0, \[Infinity]}] & /@ %
Out[32]=

Graphics3D options

All options of Graphics3D can be specified:

In[33]:=
{ResourceFunction["RiemannSurfacePlot3D"][
  w == Log[Sqrt[z] + Power[z, (3)^-1]], Re[w], {z, w}, PlotStyle -> Directive[Blue, Specularity[Yellow, 12]]],
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Log[Sqrt[z] + Power[z, (3)^-1]], Re[w], {z, w},
  PlotStyle -> Directive[Blue, Specularity[Yellow, 12]], BoxRatios -> {1, 1, 1}, FaceGrids -> All, BoxStyle -> Darker[Blue]]}
Out[33]=

Plot of the Riemann surface of a general quartic polynomial with multiple options specified:

In[34]:=
ResourceFunction[
 "RiemannSurfacePlot3D"][-1 + z (-(1 + I) z^2 + z - 1) - w (1 + (z - 1) z (z - I)) + I w^2 ( (z - 1) z^2 - 1) - (z ((1 + I) + z) - I) w^3 == 0, Re[w], {z, w}, PlotRange -> 6.5 {-1, 1}, ViewPoint -> {3.3, 0.49, 0.6}, PlotStyle -> Directive[Specularity[GrayLevel[1], 3], RGBColor[
   0.880722, 0.611041, 0.142051]], Boxed -> False,
 Lighting -> {{"Ambient", Hue[0.65, 0.6, 0.6]}, {"Directional", RGBColor[0.7, 0, 0], ImageScaled[{3, 0, 2}]}, {"Directional", RGBColor[0, 0.7, 0], ImageScaled[{1.5`, 1.5`, 2}]}, {"Directional", RGBColor[
    0, 0, 0.7], ImageScaled[{0, 3, 2}]}}]
Out[34]=

Applications

Show the Riemann surfaces for the simple power functions colored by the argument of w:

In[35]:=
Table[ResourceFunction["RiemannSurfacePlot3D"][w == z^(1/n), Im[w], {z, w},
                       ImageSize -> 180, PlotLabel -> w == z^(1/n), ColorFunction -> (Directive[Opacity[0.6], ColorData["BalancedHue"][(Arg[#2] + Pi)/(2 Pi)]] &)],
             {n, 2, 6}]
Out[35]=

Replacing z zn+z-n in the last example gives more complicated surfaces with a pole at z=0:

In[36]:=
Table[ResourceFunction["RiemannSurfacePlot3D"][
  w == Power[z^n - 1/z^n, (n)^-1], Im[w], {z, w}, ImageSize -> 180, PlotStyle -> Directive[Opacity[0.6], Purple]],
           {n, 2, 6}]
Out[36]=

Riemann surfaces of general cubics (in total degree) polynomials might or might not have poles:

In[37]:=
{ResourceFunction["RiemannSurfacePlot3D"][ z w^2 + z^2 w + z w + 1 == 0, Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][ w^3 + z w + z - w - 2 == 0, Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][ z^2 w + I w^3 - z w - I z - 3 == 0, Re[w], {z, w}]}
Out[37]=

Real parts of logarithms typically show (logarithmic) singularities, visible as long thin tubes extending up or down. Imaginary parts often are bounded.:

In[38]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == Log[z^3 - 1], Re[w], {z, w}, PlotLabel -> Re[w]],
 ResourceFunction["RiemannSurfacePlot3D"][w == Log[z^3 - 1], Im[w], {z, w}, PlotLabel -> Im[w]]}
Out[38]=

Logarithmic and algebraic branch points can be at the same z-values:

In[39]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == Log[z] + Sqrt[z], Im[w], {z, w}, "ShowBranchPoints" -> True],
 ResourceFunction["RiemannSurfacePlot3D"][w == Log[z] * Sqrt[z], Re[w], {z, w}, "ShowBranchPoints" -> True]}
Out[39]=

Properties and Relations

Inverse trigonometric functions can be expressed through logarithms and so the Riemann surfaces of such functions show logarithmic branch points:

In[40]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == ArcTan[1/( z^(1/3) - 1)], Im[w], {z, w}]
Out[40]=
In[41]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == 1 - 2 ArcTan[z] + ArcTan[z]^2, Im[w], {z, w}]
Out[41]=
In[42]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == ArcSin[Sqrt[z^5 - 1]], Re[w], {z, w}],
  ResourceFunction["RiemannSurfacePlot3D"][w == ArcSin[Sqrt[z^5 - 1]],
   Im[w], {z, w}]}
Out[42]=

Tow Riemann surfaces of functions containing square roots and logarithms:

In[43]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[Log[z + z^2]], Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][w == -2 Sqrt[z] + Log[z], Re[w], {z, w}]}
Out[43]=

When displaying the real or imaginary part vertically, Riemann surfaces can potentially separate into disconnected parts:

Linear combinations of Re(w) and Im(w) typically result in connected Riemann surfaces:

In[44]:=
 ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[1 + Sqrt[Log[z]]],
  Re[w] + Im[w], {z, w}, ViewPoint -> {3, -3, 0}]
Out[44]=

The Riemann surface of also splits into separate (intersecting, but not smoothly connected) pieces:

In[45]:=
ResourceFunction["RiemannSurfacePlot3D"][w == (z^3)^(1/3) , Im[w], {z, w}]
Out[45]=

The Riemann surface of w=2log(z)-log2(z) also splits into separate pieces:

In[46]:=
 ResourceFunction["RiemannSurfacePlot3D"][w == 2 Log[z] - Log[z^2] , Im[w], {z, w}, ViewPoint -> {2, 2, 0}]
Out[46]=

Note that the classic identity log2(z)=2log(z) holds only for positive real z:

In[47]:=
{FullSimplify[2 Log[z] - Log[z^2]], FullSimplify[2 Log[z] - Log[z^2], z > 0]}
Out[47]=

Expressions containing square roots and logarithms that become equal after PowerExpand are often not equivalent for all complex numbers. Here is an example:

In[48]:=
PowerExpand[Sqrt[(1 - z^4)/(1 + z^4)] - Sqrt[1 - z^4]/Sqrt[1 + z^4]]
Out[48]=
In[49]:=
ComplexPlot3D[
 Sqrt[(1 - z^4)/(1 + z^4)] - Sqrt[1 - z^4]/
  Sqrt[1 + z^4], {z, -2 - 2 I, 2 + 2 I}, Exclusions -> {}, PlotRange -> All, ColorFunction -> (Gray &)]
Out[49]=

But the Riemann surfaces of such expressions are identical:

In[50]:=
{ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[1 - z^4]/Sqrt[1 + z^4], Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[(1 - z^4)/(1 + z^4)], Re[w], {z, w}]}
Out[50]=

In the following example, asymptotically approaches a constant. The cube root shows the three values of the constant:

In[51]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Power[(1 + z^6)/(1 - z^6), (3)^-1], Im[w], {z, w}, BranchPointPlotRangeFactor -> 2]
Out[51]=

Using a logarithm instead shows a Riemann surface with infinitely many sheets (we display 5 = 4+1/2+1/2):

In[52]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Log[(1 + z^6)/(1 - z^6)], Im[w], {z, w}, "BranchPointPlotRangeFactor" -> 2, "LogSheets" -> {-2, -1, 0, 1, 2}]
Out[52]=

The Riemann surface of roots of polynomials displayed as the real and imaginary part are typically visually quite similar (note the slightly different orientation):

In[53]:=
{ResourceFunction["RiemannSurfacePlot3D"][
  w == Power[8 - 3 z - 2 z^4 + z^7, (3)^-1], Re[w], {z, w}, PlotStyle -> Opacity[0.6]],
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Power[8 - 3 z - 2 z^4 + z^7, (3)^-1], Im[w], {z, w}, PlotStyle -> Opacity[0.6]]}
Out[53]=

For functions containing logarithms, the real and imaginary parts typically look quite different:

In[54]:=
{ResourceFunction["RiemannSurfacePlot3D"][w == Log[z + Sqrt[z^3 - 4]],
   Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][w == Log[z + Sqrt[z^3 - 4]],
   Im[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][w == Log[z + Sqrt[z^3 - 4]],
   Im[w] - Re[w]/2, {z, w}]}
Out[54]=

Riemann surfaces constructed from nested radicals can take on a large variety of shapes:

In[55]:=
{ ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[Sqrt[z] + z^2], Im[w], {z, w}, ViewPoint -> {-3.08, -1.035, 0.940}],
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[z - Sqrt[z^3 - 1]], Re[w], {z, w}, ViewPoint -> {-2.98, 1.33, 0.89}]}
Out[55]=

Compare the result of RiemannSurfacePlot3D with two other construction methods for Riemann surfaces:

In[56]:=
 ResourceFunction["RiemannSurfacePlot3D"][w^4 == 1 - z^4, Im[w], {z, w}]
Out[56]=

For Riemann surfaces defined through bivariate polynomials one can separate the real and imaginary parts and eliminate variables. The next inputs computes an implicit form of v=Im(w) as a functions of x=Re(z) and y=Im(z) for w3=1-z4:

In[57]:=
xyvResultant = Resultant[#1, #2, u] & @@ ComplexExpand[ReIm[(u + I v)^4 - (1 - (x + I y)^4)]] // Factor
Out[57]=

The implicit form is a total degree 16 trivariate polynomial:

In[58]:=
Collect[Last[xyvResultant], v, FullSimplify]
Out[58]=

Using ContourPlot3D we obtain the following surface:

In[59]:=
ContourPlot3D[
 Evaluate[xyvResultant == 0], {x, -1.2, 1.2}, {y, -1.2, 1.2}, {v, -1.4, 1.4}, PlotPoints -> 60,
 RegionFunction -> (Norm[{#1, #2}] <= 1.2 &), Mesh -> None, BoxRatios -> {1, 1, 1.61}, Axes -> False, PlotRange -> All]
Out[59]=

Alternatively one can use Plot3D to plot every sheet and then show all sheets (note the gaps that arise from the Exclusions option of Plot3D):

In[60]:=
Show[Table[
  Plot3D[Evaluate[ Im[Exp[2 Pi I j/4] (1 - (x + I y)^4)^(1/4)]] , {x, -1.2, 1.2}, {y, -1.2, 1.2},
   RegionFunction -> (Norm[{#1, #2}] <= 1.2 &),
   PlotRange -> All, Mesh -> None, BoxRatios -> {1, 1, 1.61}, Axes -> False],
  {j, 0, 3}]]
Out[60]=

Possible Issues

Only multi-valued functions are plotted:

Out[60]=

Even simple-looking functions with multiple logarithmic branch points can generates plots with many sheets:

In[61]:=
ResourceFunction["RiemannSurfacePlot3D"][w == ArcSin[z]/ArcSinh[z], Re[w] + Im[w], {z, w}]
Out[61]=
In[62]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Sqrt[ArcCos[z]/ArcSin[z]], Re[w], {z, w}, ViewPoint -> {3, -3, 0}]
Out[62]=

Neat Examples

Compare the Riemann surface with the plaster model (left) from Schilling's catalog (image from the Göttingen Collection of Mathematical Models and Instruments) with the plot from RiemannSurfacePlot3D (right):

In[63]:=
GraphicsRow[{Show[plasterModelImage, ImageSize -> 320], ResourceFunction["RiemannSurfacePlot3D"][w == Sqrt[z^2 - 1], Im[w], {z, w},
                             BoxRatios -> {1, 1, 1}, PlotStyle -> GrayLevel[0.7], ViewPoint -> {2.85, 0.75, 1.6},
                            Lighting -> "Neutral", Boxed -> False, Background -> GrayLevel[0.25]]}]
Out[63]=

Two Riemann surfaces of quotients of square roots and logarithms:

In[64]:=
{ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[1 - z^4]/Log[1 - z^6], Re[w], {z, w}, PlotStyle -> Opacity[0.8]],
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Log[1 - z^4]/Sqrt[1 - z^6], Re[w], {z, w}, PlotStyle -> Opacity[0.8]]}
Out[64]=

The rotated (for a more interesting look) Riemann surface of :

In[65]:=
 ResourceFunction["RiemannSurfacePlot3D"][w == ArcSin[Log[z]] , Im[w], {z, w},
 ViewVertical -> {-1, 0, 0}, ViewPoint -> {-1.88, 2.55, 1.2}, BoxRatios -> {1, 1, 2.5}]
Out[65]=

The rotated (for a more interesting look) Riemann surface of :

In[66]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Sqrt[Log[z]], {Re[z], Im[w], Im[z]}, {z, w},
 LogSheets -> Range[-3, 3], ViewPoint -> {1.4, 0, -3.08}, BoxRatios -> {1, 3, 1},
 PlotStyle -> Directive[GrayLevel[0.4], Specularity[Red, 12]]]
Out[66]=

The imaginary parts of of the Riemann surface of log2(z) reminds on nested tops:

In[67]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Log[z]^2, Im[w], {z, w},
  LogSheets -> Range[-5, 5], PlotStyle -> Directive[Opacity[0.2], Darker[Green, 0.8], Specularity[Yellow, 20]]]
Out[67]=

The Riemann surface of colored according to the argument of w:

In[68]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Power[I - z^4, (4)^-1], Im[w], {z, w}, ColorFunction -> (Directive[Opacity[0.6], Hue[(Arg[#2] + Pi)/(2 Pi)]] &),
 PlotPoints -> {90, 60}, Boxed -> False]
Out[68]=

Color the real part according to the imaginary part:

In[69]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Log[ Log[z]^2 - 1], Im[w], {z, w}, ColorFunction -> (ColorData["DarkRainbow"][ArcTanh[Re[#2]/5]] &)]
Out[69]=

Color the sheets according to the argument of the z-value:

In[70]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Log[ Sqrt[z] + Power[z, (3)^-1] ], Re[w], {z, w}, "LogSheets" -> Range[-3, 3], ColorFunction -> (ColorData["DarkRainbow"][Cos[Arg[#1]/2]] &)]
Out[70]=

The internals of this Riemann surface of a ratio of arctan functions:

In[71]:=
Show[ResourceFunction["RiemannSurfacePlot3D"][
  w == (ArcTan[z] + ArcTan[\[Pi] - z])/ArcTan[\[Pi]/2 - z], Re[w], {z, w}, "LogSheets" -> {-1, 0},
   PlotStyle -> Directive[ Pink, Specularity[Pink, 6]]], PlotRange -> {All, {0, 6}, {-6, 6}}, ViewPoint -> {1, -3, 0.5}]
Out[71]=

Color the surface blue when the real part of w is greater than the imaginary part, red otherwise:

In[72]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == (1 + Power[z, (3)^-1])/(1 + Sqrt[z] + Power[z^5, (6)^-1]), Re[w], {z, w}, ColorFunction -> (Directive[Opacity[0.6], If[Re[#2] > Im[#2], Blue, Red]] &)]
Out[72]=

The complicated Riemann surface of the square root of the logarithm of a polynomial:

In[73]:=
{ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[Log[z + z^3 + z^5]], Re[w], {z, w}],
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[Log[z + z^3 + z^5]], Im[w], {z, w}]}
Out[73]=

Plot a camouflaged Riemann surface:

In[74]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == (Sqrt[z + 1] - Sqrt[z - 1])/(Sqrt[z + I] + Sqrt[z - I]), Re[w], {z, w}, ColorFunction -> (ColorData["GreenBrownTerrain"][RandomReal[]] &), ViewPoint -> {3.03, -1.51, 0.12}]
Out[74]=

Plot a simple Riemann surface:

In[75]:=
rs = ResourceFunction["RiemannSurfacePlot3D"][
  w == Power[z, (3)^-1]/(6 + Sqrt[z - 1]) , Im[w], {z, w}, PlotPoints -> {80, 40}, ColorFunction -> (Directive[Opacity[0.8], ColorData["AuroraColors"][Cos[ Arg[2 #2] /2]]] &)]
Out[75]=

“Roughen” the Riemann surface by moving of the surface by small random amounts:

In[76]:=
roughen[rs, 0.0025]
Out[76]=

Add the Union Jack into the patches of a Riemann surface as a texture:

In[77]:=
 ResourceFunction["RiemannSurfacePlot3D"][w == Power[1 + z^4, (4)^-1],
   Re[w], {z, w}, BoxRatios -> {1, 1, 1}, PlotStyle -> Opacity[0.8], Boxed -> False] /. GraphicsComplex[pts_, __] :> ListPlot3D[pts, PlotStyle -> Texture[Entity["Country", "UnitedKingdom"][
       EntityProperty["Country", "Flag"]]],
                                                                      \
                Mesh -> None, BoundaryStyle -> None, PlotRange -> All][[1]]
Out[77]=

A Riemann surface that slowly fades out:

In[78]:=
ResourceFunction["RiemannSurfacePlot3D"][
 w == Log[(7 - 2 z + z^3)/Sqrt[-1 + z - 3 z^3 + z^5]], Im[w], {z, w}, ViewPoint -> {1.12, -3.03, 1.02}, "ShowBranchPoints" -> True,
 ColorFunction -> (Directive[Orange, Opacity[Piecewise[{{1, Im[#2] < -8}, {1 - ((Im[#2] + 8)/18)^0.25,
          Im[#2] > -8}}]]] &)]
Out[78]=

Plot an auto-rotating Riemann surface:

In[79]:=
ResourceFunction["RiemannSurfacePlot3D"][w == Power[1 - z^8, (5)^-1], Im[w], {z, w}, "BranchPointPlotRangeFactor" -> 1.2,
  PlotPoints -> {180, 32}, Boxed -> False, SphericalRegion -> True, ViewPoint -> Dynamic[{3 Cos[Clock[2 Pi]], 3 Sin[Clock[2 Pi]], 1 + Abs[ Sin[Clock[Pi]]]}, UpdateInterval -> 0], PlotStyle -> Directive[RGBColor[
   0.8873402883377823, 0.0881874778872287, 0.20269962280609732`], Specularity[RGBColor[
    0.00826013975092077, 0.9983549796506077, 0.8536693247046465], 12]], Lighting -> {{"Ambient", RGBColor[
    0.08991790342148565, 0.4656695106684785, 0.3563096997888613]}, {"Directional", RGBColor[
    0.58565433989252, 0.20711472123320362`, 0.6773803713053297], ImageScaled[{1, -1, -2}]}, {"Directional", RGBColor[
    0.9340004634836698, 0.21091405108492345`, 0.24376150618256442`], ImageScaled[{3, -1, 3}]}, {"Directional", RGBColor[
    0.01234965817203082, 0.8702599913137037, 0.7827905082641344], ImageScaled[{1, 3, -1}]}}]
Out[79]=

Cut a Riemann surface along shifted x,y-planes:

In[80]:=
With[{colors = Table[RandomColor[], {100}]},
 Manipulate[
  ResourceFunction["RiemannSurfacePlot3D"][
   z + w + z w + z^2 + 1/w + 1/z == 1, Re[w], {z, w},
   PlotStyle -> colors, ClipPlanes -> InfinitePlane[{0, y, 0}, {{0, 0, 1}, {1, 0, 0}}]],
  {{y, 0, "cut plane"}, -3, 3}]]
Out[80]=

Smoothly change from displaying the real part to displaying the imaginary parts of :

In[81]:=
Manipulate[
 ResourceFunction["RiemannSurfacePlot3D"][
  w == Sqrt[1 - z^3], (1 - \[Sigma]) Re[w] + \[Sigma] Im[w], {z, w},
                                                                      \
 PlotStyle -> Directive[Opacity[0.8], Blue, Specularity[Yellow, 12]]],
 Row[{"Re", Control[{{\[Sigma], 0, ""}, 0, 1}], " Im"}]]
Out[81]=

By considering a Riemann surface as part of {z,w}∈ℂ2≃ℝ4, by rotating the surface and projecting into 2D space one can interactively explore the complete Riemann surface. Every angle results in a different 3D surface:

In[82]:=
Manipulate[
 ResourceFunction["RiemannSurfacePlot3D"][
  w == (Sqrt[z - 1] Sqrt[z + 1])/(
   Sqrt[z - 1] - Sqrt[
    z + 1]), {\[CurlyPhi]xy, \[CurlyPhi]xu, \[CurlyPhi]xv, \
\[CurlyPhi]yu, \[CurlyPhi]yv, \[CurlyPhi]uv}, {z, w}], Row[{"show ", Button["u(x,y)", {\[CurlyPhi]xy, \[CurlyPhi]xu, \[CurlyPhi]xv, \
\[CurlyPhi]yu, \[CurlyPhi]yv, \[CurlyPhi]uv} = {0, 0, 0, 0, 0, 0}], Button["v(x,y)", {\[CurlyPhi]xy, \[CurlyPhi]xu, \[CurlyPhi]xv, \
\[CurlyPhi]yu, \[CurlyPhi]yv, \[CurlyPhi]uv} = {0, 0, 0, 0, 0, \[Pi]/2}]}],
 Row[{"show ", Button["x(u,v)", {\[CurlyPhi]xy, \[CurlyPhi]xu, \[CurlyPhi]xv, \
\[CurlyPhi]yu, \[CurlyPhi]yv, \[CurlyPhi]uv} = {0, \[Pi]/2, \[Pi], 0, \[Pi]/2, 0}],
         Button[
    "y(u,v)", {\[CurlyPhi]xy, \[CurlyPhi]xu, \[CurlyPhi]xv, \
\[CurlyPhi]yu, \[CurlyPhi]yv, \[CurlyPhi]uv} = {0, 0, \[Pi]/2, \[Pi]/2, \[Pi], \[Pi]/2}] }],
 {{\[CurlyPhi]xy, 0, "\!\(\*SubscriptBox[\(\[CurlyPhi]\), \(x, y\)]\)"}, -Pi, Pi}, {{\[CurlyPhi]xu, 0, "\!\(\*SubscriptBox[\(\[CurlyPhi]\), \(x, u\)]\)"}, -Pi, Pi},
 {{\[CurlyPhi]xv, 0, "\!\(\*SubscriptBox[\(\[CurlyPhi]\), \(x, v\)]\)"}, -Pi, Pi}, {{\[CurlyPhi]yu, 0, "\!\(\*SubscriptBox[\(\[CurlyPhi]\), \(y, u\)]\)"}, -Pi, Pi},
 {{\[CurlyPhi]yv, 0, "\!\(\*SubscriptBox[\(\[CurlyPhi]\), \(y, v\)]\)"}, -Pi, Pi}, {{\[CurlyPhi]uv, 0, "\!\(\*SubscriptBox[\(\[CurlyPhi]\), \(u, v\)]\)"}, -Pi, Pi},
 ControlPlacement -> Left]
Out[82]=

Resource History

License Information