Face and Edge Colors

Solid Colors

The colors of surface faces and edges are setup during the object instantiation using the named argument assignments of color, facecolor, and edgecolor. With no assignments, the default color for faces and edges is the Matplotlib color ‘C0’. The assignment of three arguments can be made in several combinations and, at first, slightly confusing. From the Matplotlib Poly3DCollection code comments:

'''
Note that this class does a bit of magic with the _facecolors
and _edgecolors properties.
'''

The logic for how colors are assigned is:

  1. If color is not assigned, the color will be the ‘C0’ default color (blue).
  2. If facecolor is not assigned, facecolor will be the color.
  3. If edgecolor is not assigned, edgecolor will be the facecolor only if the color is not assigned, otherwise it will be the color.

Using three different colors for the three arguments, the eight combinations for assignment to a SphericalSurface are shown below. The most confusing is when edgecolor is not assigned, in which case it will take the value of the facecolor or color argument value ( F or CF ). In general, either use just facecolor or the combination of both facecolor and edgecolor to avoid unexpected results.

../../_images/CFEcolor.png

When the facecolors are changed after instantiation, either by colormap operations, colormapping normals or shading, the edgecolors will be reassigned. This is shown for the shading case where shading has been applied to the surface. If edges are to be shown, use the object method after shade to assign an edgecolor to the edges:

surface.set_edgecolor(edgecolor)

The script to generate the above plots is given below.

import numpy as np
from matplotlib import pyplot as plt
import s3dlib.surface as s3d
 
# 2. Setup and map surfaces .........................................
rez = 1
C,F,E = 'C2', 'gold', 'C3'

surf_C =    s3d.SphericalSurface( rez, color=C )
surf_F =    s3d.SphericalSurface( rez, facecolor=F )
surf_E =    s3d.SphericalSurface( rez, edgecolor=E )
surf_CF =   s3d.SphericalSurface( rez, color=C, facecolor=F )
surf_CE =   s3d.SphericalSurface( rez, color=C, edgecolor=E )
surf_FE =   s3d.SphericalSurface( rez, facecolor=F, edgecolor=E )
surf_0 =    s3d.SphericalSurface( rez )
surf_CFE =  s3d.SphericalSurface( rez, color=C, facecolor=F, edgecolor=E )
surf_CFEs = s3d.SphericalSurface( rez, color=C, facecolor=F, edgecolor=E ).shade()

# 3. Construct figure, add surfaces, and plot .....................

title = [    'C',    'F',    'E',    'CF',    'CE',    'FE', 'default',    'CFE',  'CFE.shade']
surf =  [ surf_C, surf_F, surf_E, surf_CF, surf_CE, surf_FE,    surf_0, surf_CFE,   surf_CFEs ]

fig = plt.figure(figsize=(5,5))
minmax = (-.7,.7)

for i in range(9) :
    ax = fig.add_subplot(331+i, projection='3d')
    ax.set_aspect('equal')
    ax.set_axis_off()
    ax.set(xlim=minmax, ylim=minmax, zlim=minmax )
    ax.set_title(title[i])
    ax.add_collection3d(surf[i])

fig.tight_layout()
plt.show()

Transparency

As described above, when the edge color is not defined during instantiation, the edgecolor will take the color assigned to the ‘color’ or ‘facecolor’, with the exception discussed further below. Edge color is also assigned for any surface coloring operation as

  • map_color_from_image
  • map_color_from_op
  • map_cmap_from_op
  • map_cmap_from_normals
  • map_camp_from_datagrid
  • shade
  • hilite

In addition, the original surface colors are assigned to sub-triangles when the ‘triangulate’ method is used. This effect is demonstrated in the Face Color Array example.

However, the apparent edge color may differ from the surface color even when edge color is directly or indirectly assigned to the surface color. This difference depends on both the edge linewidth (with default of 1.5) or the transparency of the surface face color set by the color alpha value (maximum and default of 1.0). Consider the Color Mapping Normals examples below for three different linewidths with a surface color alpha of 0.7.

../../_images/edgecolor_lw_alpha_1.png

Edges will appear from darker to lighter than the surface color as the linewidth (lw) is reduced. This is a result of the gap between faces and overlaying edges during rendering. The edge color, relative to face color is dependent both on linewidth and color alpha value. This relationship is shown in the plot below.

../../_images/edgecolor_lw_alpha_2.png

This effect is also seen in the Matplotlib Triangular 3D surfaces example where the linewidth is 0.2 for default color (alpha = 1.0). The apparent ‘lighter’ or ‘darker’ edge color is relative to the axis background color on which the surface object is added. This effect is diminished for large rez surfaces.

To change the surface alpha or linewidth, the available surface methods are:

surface.set_linewidth(width)
surface.set_surface_alpha(alpha)

When the facecolor has an alpha channel value less than one, the edges will be visible, even if edge color is given the alpha value using the default line width. With additional shading, the edges will show the shaded colors. This is seen in the following plot:

To hide the edges when using color with a transparency, assign the linewidth using the plot above for the linewidth based on the color alpha value, as shown for the right surface.

../../_images/CFEcolor2.png

The script fragment to generate the above plot is given below.

Fa = colors.to_rgba('gold',0.2)
Ea = colors.to_rgba('C3', 0.00)

surf_Fa_s =    s3d.SphericalSurface( rez, color=Fa ).shade()
surf_FaEa_a =  s3d.SphericalSurface( rez, facecolor=Fa, edgecolor=Ea ).shade()
surf_FaW0_a =  s3d.SphericalSurface( rez, color=Fa, linewidth=0.015 ).shade()
surf_set_a  =  s3d.SphericalSurface( rez, color='gold').set_surface_alpha(0.2).shade()

An alternative is to first assign a color, then use the surface method set_surface_alpha. This method, by default, will set the linewidth adjusted to the alpha argument used in the method call. To override the default, assign adjustlw = False in the method call.

To hide the faces but still apply shading or a color map to the edges, use the object method:

surface.set_facecolor(transparent_color)

where transparent_color is any color with the alpha channel set to zero.

../../_images/CFEcolor3.png

Note

As described in the Hello World tutorial, edges can be displayed using the object property edges. In this case, the edge property is an object of class ColorLine3DCollection having the default color. Color variations are then available for this object using the line color mapping methods. See Face Edge Visualizations

The script fragment to generate the above plot is given below.

surf_Fs =  s3d.SphericalSurface( rez, color=F ).shade()
surf_Fs.set_facecolor([0,0,0,0])
surf_cmap =  s3d.SphericalSurface( rez, color=F )
surf_cmap.map_cmap_from_normals('hsv')
surf_cmap.set_facecolor([0,0,0,0])