# Notes¶

The following is a list of problems which may occur during object construction and rendering with an explanation of the cause and possible solution.

1. The object is displayed either too large or too small.
When objects are added to the 3D axes, the axis limits are not automatically set by Matplotlib, as with 2D plots. Either the limits for each axis must be explicitly set using the axes3d set methods (see numerous examples), or the S3Dlib function auto_scale must be used to set the axes limits based on the objects added to the axes. See the Scaling tutorial.
_

2. The surface or line is not completely displayed or not displayed at all.
The construction of base surfaces is in the axes domain [-1,1]. Default geometric mapping will occur within this domain. There are two possible solutions to this problem. First, the base surface domains can be changed using the object domain method prior to any mapping, for example Clipping Surface and Contours or Color Space. Second, the domain of the mapping function must be defined within the [-1,1] domain, for example Function Plots, z = f(x,y). In addition, the axes must be appropriately scaled, as noted above.
_

3. The object appears distorted.
This is usually a result of different ranges used for the three axis. See Object Axis Setting.
_

4. Two separate surface objects added to the axes do not intersect correctly in a particular view.
The faces of two separate surfaces do not preserve the z-order among the faces. When the centers of objects are sequentially aligned in a particular view, this is not a problem for multiple objects added to the axes. This is the case for the above visualization. However, when this is not the case, the usual solution is to create a single object by adding the two separate objects together. Then add the composite object to the axes. An example of this is shown in Surface Addition.
_

5. Surface geometry and color is very much not what was expected.
The resulting visualization of a surface is dependent on the sequence of geometry, color and transformation operations. A detailed discussion of this is provided in the OOPs, Order of Operations guide. Also, examine the functions used in each of the operations to create the surface. Apply each operation separately to create a visualization, confirming the result from each function.
_

6. The following error occurs:
``` ValueError: Can not reset the axes. You are probably trying to re-use an artist in more than one Axes which is not supported. ```
Matplotlib does not allow an object to be added to the same figure multiple times, even on different axes. This can be corrected by using multiple copies of the same object using the Python copy method. For example, see the second figure in the Cylindrical Surface Contours example.
_

7. Line objects may incorrectly overlap surface objects when both are added to the same axes.
These two object types don’t have a relative z-order. This problem may be minimized using line fading ( Image Value Clipping ) or line clipping ( Earth Elevation Projected Contours ).
_

8. The following error occurs:
``` ValueError: all the input array dimensions except for the concatenation axis must match exactly ```
This error will occur during object addition. Surfaces can only be added together if both surfaces have triangular or quadrilateral faces. The solution is to use the triangulate method for the surface with quadrilateral faces, then add the surfaces together.
_

9. The following error occurs:
``` ValueError: No surface.contourLines were found. ```
This error will occur in the case for one of the following two conditions for a single contour:
The intersection surface is external to the surface, with solution being to reassign an appropriate value to the dist argument in the calling method.
Secondly, the intersection surface only intersects vertices of the calling surface with the result that no intersection face edges are found. The solution is to make a visually imperceptible translation of either the intersection surface or calling surface object.
_

10. The following warning occurs:
``` Surface contourLines not found for dist value of 0.0 ```
This error will occur if one of multiple contours in a set is not found (the one at 0.0). This error also indicates that visualization will appear to be missing a contour. The intersection surface only intersects vertices of the calling surface with the result that no intersection face edges are found. The solution is to make a visually imperceptible translation of the calling surface object.
_

11. The functional geometric operation on an object results in a ‘wildly’ incorrect geometry.
Surface objects have native coordinates of either Cartesian, polar, cylindrical or spherical coordinates, depending on the class. The function must return coordinates in native coordinates. If the function returns Cartesian coordinates, set the map_to_geom_from_op method argument returnxyz to True. Also, all classes have the method coor_convert which can be conveniently used for coordinate transformations.
_

12. The functional geometric operation on a composite object results in a ‘wildly’ incorrect geometry.
Surface objects of different basetypes may be added together to form one composite object. This single object uses the xyz Cartesian coordinates as the native coordinate for all subsequent operations. The function for the composite must return xyz coordinates for a composite object.
_

13. The shading and high-lighting do not appear correctly on a surface when placed on a specific axes.
Shade, hilite, etc. methods use coordinate directions for the light source. When surfaces are plotted on axes of different lengths, the apparent light source directions will be distorted. As a result, the light source directions should also be scaled similar to the axes scaling.
_

14. The linewidth or edgecolor are not correct on a composite object.
For a composite object, linewidth and edgecolor of the added objects will not be used for the composite object. Linewidth and edgecolor can only be set for one object, which is the result of the addition operator.
This is a particular problem when composites are constructed from surfaces with different transparencies which result with face edges incorrectly becoming visible. The solution ‘may’ be to not add the surfaces together and use an alternative view direction with the axes view_init method.
_

15. The edgecolor of a surface object is not visible when initially set.
Surface colormapping, shading, and hiliting set the surface colors, including edgecolor. As a result, any assignment of edgecolor must be made after surface colors are set.
_

16. The undesired appearance of face edges appear for a surface object with a level of transparency.
It is generally better to set the alpha value using the surface set_surface_alpha method rather than setting the color or facecolor argument during instantiation of the object. The set_surface_alpha method will automatically set a line width which will not expose the edges. See, for example, the Transparency guide.
_

17. Undesired appearance of face edges appear for a faded surface object.
Since since face transparency affects the visibility of the edges, gradients in transparency will expose edges invarious regions of the surface ( see the Transparency guide ). This affect ‘may’ be minimized by setting the line_width but can not be eliminated.
_

18. Lines appear ‘dotted’ with a level of transparency at segment boundaries.
The line must be subdivided into smaller segments, for example using a larger value for rez.
_

19. When using the ax argument for shading, the face colors show abrupt color changes on the surface.
The usual cause is that the axes view_init is called after shading is applied. The surface shading method, when using the ax argument, must occur after the axes view_init is called.
_

20. When using the ax argument for inner and outer surface coloring, the face colors show abrupt color changes on the surface.
The usual cause is that the three coordinate axes are not scaled equally. The axes must be equally scaled by setting each coordinated or using the scaling function auto_scale with the uscale or rscale arguments.
_

21. Some faces polygons incorrectly overlap or intersect other face polygons depending on the view.
The z-order among the faces is determined from the sequence of face centers. This problem may occur when polygons intersect, due to relative orientation and sizes. Several solution may apply:

• Increase the rez for surface instantiation.
• Use an alternative basetype for surface object instantiation. See Selecting a Base.
• If a composite, adjust rez of the two initial surfaces, generally having the same rez for all surfaces.
• Use the triangulate method to subdivide the faces into smaller triangles.
• For projected lines, increase the lrez argument of the line methods. See Surface Rendering Control.
• Make a minor change in view direction elev or azim arguments using the view_init axes method.

The sequence of operations to produce a visualization may require setting color and line widths at various steps in the development. The following object methods inherited from the Matplotlib Poly3DCollection and Line3DCollection classes may be useful for this purpose:

```surface.set_color( color )
surface.set_facecolor( color )
surface.set_edgecolor( color )
surface.set_linewidth( width )
line.set_color( color )
line.set_edgecolor( color )
line.set_linewidth( width )
```

The intro figure shows three separate objects added to the 3D axes. It was not necessary to construct a single object using addition since the object centers progressed from the axes view in a sequential order. The custom colormaps and Python script follows:

```import numpy as np
from matplotlib import pyplot as plt
import s3dlib.surface as s3d
import s3dlib.cmap_utilities as cmu

#.. Lightbulb

# 1. Define functions to examine ....................................
Rnk, zeta = .85, 0.5*np.pi/2.0
W = (1+Rnk)*np.sin(zeta) - Rnk
d, H = 0.1, 0.6*W

def bulb(rtp):
def neck(rp) :
r,p = rp
b = (np.pi/2 -zeta)*(np.pi-p)/zeta
x = (1+Rnk)*np.cos(zeta) - Rnk*np.sin(b)
y = (1+Rnk)*np.sin(zeta) - Rnk*np.cos(b)
R = np.sqrt( x*x + y*y)
P = np.pi - np.arctan(y/x)
return np.array([R,P])
RP = np.array(rtp)[[0,2]]
R,P = np.where( RP[1] > np.pi-zeta, neck(RP), RP)
return R, rtp[1], P

def base(rtz) :
r,t,z = rtz
R = 1-d*(1-np.cos(6.5*(1-z)*np.pi/2))/2
Z = H*(z-1)-(1+Rnk)*np.cos(zeta)
return W*R,t,Z

def tipShape(rtp) :
r,t,p = rtp
R = 1 - 0.25*(1-np.cos(4*p))/2
return R,t,p

# 2. Setup and map surfaces .........................................
nlng = 2*36
cmap2 = cmu.section_cmap('copper',0.5,1,'section_copper')
cmap3 = cmu.binary_cmap('dimgrey','w','bin_dgrey_w',0.75)

top = s3d.SphericalSurface.grid(nlng,2*nlng,'r',color='w')
top.map_cmap_from_op(lambda c : c[0], cmap1)
top.map_geom_from_op(bulb)

btm = s3d.CylindricalSurface.grid(9*8,2*nlng,'r')
btm.map_geom_from_op(base)
btm.map_cmap_from_op(lambda c : c[0],cmap2)

tip = s3d.SphericalSurface.grid(20,36,'r')
tip.map_cmap_from_op(lambda c : c[2], cmap3)
tip.map_geom_from_op(tipShape)
reshape =( W-0.3*d)*np.array([1,1,0.5])
shift = [0,0,-(2*H+(1+Rnk)*np.cos(zeta) )]
tip.transform(scale=reshape,translate=shift)

# 3. Construct figure, add surfaces, and plot ......................
minmax = (-1.0,1.0)
fig = plt.figure(figsize=plt.figaspect(1), facecolor='w' )
ax = plt.axes(projection='3d',facecolor='w')
ax.set_aspect('equal')
ax.set(xlim=minmax, ylim=minmax, zlim=(-1.5,0.5))
ax.set_axis_off()
ax.view_init(7)