---
name: coot-figure-making
description: "Best practices for creating publication-quality molecular graphics figures in Coot using user-defined colors, ribbons, and molecular representations"
---

# Coot Figure-Making Best Practices

This skill provides guidance for creating publication-quality molecular graphics figures in Coot, with emphasis on custom coloring schemes and ribbon representations.

## Critical Rule: Use Function Wrappers

**ALWAYS wrap complex multi-line code in functions when using the MCP interface.**

### Why?

Multi-line code executed directly (without a function wrapper) can corrupt the Python interpreter if any error occurs. Function wrappers provide proper error handling and prevent interpreter crashes.

### Pattern

```python
# Step 1: Define the function with run_python_multiline()
def my_figure_function():
    # ... complex code here ...
    return result

# Step 2: Call the function with run_python()
my_figure_function()
```

### Example

```python
# ❌ BAD - Direct multi-line execution (can crash interpreter)
ss_info = coot.get_header_secondary_structure_info(0)
strands = ss_info['strands']
# ... more code ...

# ✅ GOOD - Function wrapper (safe error handling)
def setup_figure():
    ss_info = coot.get_header_secondary_structure_info(0)
    strands = ss_info['strands']
    # ... more code ...
    return "Done"

setup_figure()
```

## User-Defined Color Workflow

### Overview

Coot's user-defined color system allows custom coloring of specific selections. The workflow has strict ordering requirements:

1. Define color palette with `set_user_defined_colours_py()`
2. Assign colors to selections with `set_user_defined_atom_colour_by_selection_py()`
3. Create representation that uses those colors
4. **Critical**: Recreating a representation requires reassigning ALL colors

### Color Indices

- Indices 0-59: Reserved for Coot's internal colors
- Indices 60+: Available for user-defined colors
- Convention: Start at 60 and increment (60, 61, 62, etc.)

### Basic Pattern

```python
def setup_colors():
    # Step 1: Define colors (RGB values 0.0-1.0)
    blue = [0.3, 0.6, 1.0]
    orange = [1.0, 0.5, 0.0]
    
    # Step 2: Set color palette
    coot.set_user_defined_colours_py([
        (60, blue),
        (61, orange)
    ])
    
    # Step 3: Assign colors to selections (MMDB format)
    color_assignments = [
        ("//A/10-50", 60),   # Blue for residues 10-50
        ("//A/100-150", 61)  # Orange for residues 100-150
    ]
    coot.set_user_defined_atom_colour_by_selection_py(imol, color_assignments)
    
    # Step 4: Create representation
    # //! @param secondary_structure_usage_flag  0 (USE_HEADER) i.e. use the secondary structure defined in the header (if any),
    # //                                         1 (DONT_USE) or
    # //                                         2 (CALC_SECONDARY_STRUCTURE)
    # //                                         the DONT_USE case will give a worm-like backbone representation
    # as a rule of thumb, use 2 when there is no HELIX/SHEET records in the input file.
    # if the user wants "worm-like" then they will (should) make it clear that that is the case.
    coot.add_ribbon_representation_with_user_defined_colours(imol, "My Figure", secondary_structure_usage_flag)
    
    return "Colors applied"
```

## Secondary Structure Coloring

### Using PDB Header Information

The most reliable way to color by secondary structure is to use the annotations in the PDB header.

```python
def color_by_secondary_structure(imol):
    # Get secondary structure from PDB header
    ss_info = coot.get_header_secondary_structure_info(imol)
    strands = ss_info['strands']
    helices = ss_info['helices']
    
    # Build MMDB selection strings for strands
    strand_selections = []
    for strand in strands:
        chain = strand['initChainID']
        start = strand['initSeqNum']
        end = strand['endSeqNum']
        selection = f"//{chain}/{start}-{end}"
        strand_selections.append(selection)
    
    # Build MMDB selection strings for helices
    helix_selections = []
    for helix in helices:
        chain = helix['initChainID']
        start = helix['initSeqNum']
        end = helix['endSeqNum']
        selection = f"//{chain}/{start}-{end}"
        helix_selections.append(selection)
    
    # Define colors
    blue = [0.3, 0.6, 1.0]        # Beta strands
    purple = [0.5, 0.3, 0.5]      # Helices
    
    coot.set_user_defined_colours_py([
        (60, blue),
        (61, purple)
    ])
    
    # Assign colors
    strand_assignments = [(sel, 60) for sel in strand_selections]
    helix_assignments = [(sel, 61) for sel in helix_selections]
    all_assignments = strand_assignments + helix_assignments
    
    coot.set_user_defined_atom_colour_by_selection_py(imol, all_assignments)
    
    # Create ribbon
    coot.add_ribbon_representation_with_user_defined_colours(imol, "Secondary Structure", secondary_structure_usage_flag)
    
    return f"{len(strand_selections)} strands, {len(helix_selections)} helices"
```

### Adding Manual Secondary Structure Annotations

Sometimes secondary structure elements aren't annotated in the PDB header. You can add them manually:

```python
def add_missing_helix(imol):
    # Get existing colors
    ss_info = coot.get_header_secondary_structure_info(imol)
    strands = ss_info['strands']
    helices = ss_info['helices']
    
    # Build all selections (as before)
    strand_selections = [...]
    helix_selections = [...]
    
    # Add manually identified helix
    helix_selections.append("//A/135-139")
    
    # Reassign ALL colors and recreate ribbon
    # (must include ALL selections every time)
    coot.set_user_defined_colours_py([...])
    all_assignments = strand_assignments + helix_assignments
    coot.set_user_defined_atom_colour_by_selection_py(imol, all_assignments)
    coot.add_ribbon_representation_with_user_defined_colours(imol, "Updated", secondary_structure_usage_flag)
    
    return "Helix added"
```

### Critical Rule: Reassign All Colors When Recreating

**When you recreate a ribbon representation, you MUST reassign ALL color selections, not just the new ones.**

```python
# ❌ BAD - Only assigns new helix, strands lose their color
coot.set_user_defined_atom_colour_by_selection_py(imol, [("//A/135-139", 61)])
coot.add_ribbon_representation_with_user_defined_colours(imol, "New", secondary_structure_usage_flag)

# ✅ GOOD - Reassigns everything
all_assignments = strand_assignments + helix_assignments + new_helix
coot.set_user_defined_atom_colour_by_selection_py(imol, all_assignments)
coot.add_ribbon_representation_with_user_defined_colours(imol, "New", secondary_structure_usage_flag)
```

## Highlighting Specific Features

### Extracting Residues to Separate Molecules

To highlight specific residues (like active site residues, ligands, chromophores), extract them to a new molecule:

```python
def highlight_feature(imol, selection, color_rgb, bond_thickness=10.0):
    # Extract to new molecule
    feature_imol = coot.new_molecule_by_atom_selection(imol, selection)
    
    if not coot.is_valid_model_molecule(feature_imol):
        return -1
    
    # Define color
    color_index = 62  # Use a different index than strands/helices
    coot.set_user_defined_colours_py([(color_index, color_rgb)])
    
    # Assign color
    coot.set_user_defined_atom_colour_by_selection_py(feature_imol, [(selection, color_index)])
    
    # Add representation with thick bonds
    #
    # //! @param secondary_structure_usage_flag  0 (USE_HEADER) i.e. use the secondary structure defined in the header (if any),
    # //                                         1 (DONT_USE) or
    # //                                         2 (CALC_SECONDARY_STRUCTURE)
    # //                                         the DONT_USE case will give a worm-like backbone representation
    # as a rule of thumb, use 2 when there is no HELIX/SHEET records in the input file.
    # if the user wants "worm-like" then they will (should) make it clear that that is the case.
    coot.add_molecular_representation_py(
        feature_imol,
        selection,
        "userDefined",  # Use user-defined colors
        "Bonds"
        secondary_structure_usage_flag
    )
    
    # Make bonds thicker for emphasis
    coot.set_bond_thickness(feature_imol, bond_thickness)
    
    return feature_imol

# Example: Highlight chromophore in orange
highlight_feature(0, "//A/66", [1.0, 0.5, 0.0], 10.0)
```

## View Setup

### Centering and Zooming

```python
def setup_view(chain_id, resno, zoom_level=200):
    # Center on specific residue
    coot.set_go_to_atom_chain_residue_atom_name(chain_id, resno, "CA")
    
    # Set zoom level
    # 150-300: Whole molecule overview
    # 50-100: Domain level
    # 20-50: Residue detail
    coot.set_zoom(zoom_level)
```

### Hiding Bond Representation

For ribbon-only figures, hide the bond representation:

```python
# Hide bonds for molecule 0
coot.set_mol_displayed(0, 0)

# Show bonds again if needed
coot.set_mol_displayed(0, 1)
```

## Complete Example: GFP Beta Barrel Figure

This example creates a publication-quality figure showing GFP's beta barrel structure with colored secondary structure and highlighted chromophore.

```python
def make_gfp_figure():
    """
    Create a figure showing GFP with:
    - Blue beta barrel strands
    - Dark pastel helices
    - Orange chromophore with thick bonds
    """
    imol = 0  # GFP molecule
    
    # Get secondary structure
    ss_info = coot.get_header_secondary_structure_info(imol)
    strands = ss_info['strands']
    helices = ss_info['helices']
    
    # Build strand selections
    strand_selections = []
    for strand in strands:
        sel = f"//{strand['initChainID']}/{strand['initSeqNum']}-{strand['endSeqNum']}"
        strand_selections.append(sel)
    
    # Build helix selections
    helix_selections = []
    for helix in helices:
        sel = f"//{helix['initChainID']}/{helix['initSeqNum']}-{helix['endSeqNum']}"
        helix_selections.append(sel)
    
    # Add manually identified helix (not in PDB header)
    helix_selections.append("//A/135-139")
    
    # Define colors
    blue = [0.3, 0.6, 1.0]           # Beta strands
    dark_pastel = [0.5, 0.3, 0.5]    # Helices
    orange = [1.0, 0.5, 0.0]         # Chromophore
    
    coot.set_user_defined_colours_py([
        (60, blue),
        (61, dark_pastel),
        (62, orange)
    ])
    
    # Assign colors to secondary structure
    strand_assignments = [(sel, 60) for sel in strand_selections]
    helix_assignments = [(sel, 61) for sel in helix_selections]
    all_assignments = strand_assignments + helix_assignments
    coot.set_user_defined_atom_colour_by_selection_py(imol, all_assignments)
    
    # Create ribbon
    coot.add_ribbon_representation_with_user_defined_colours(imol, "GFP Barrel", secondary_structure_usage_flag)
    
    # Hide bonds
    coot.set_mol_displayed(imol, 0)
    
    # Extract and highlight chromophore
    chrom_imol = coot.new_molecule_by_atom_selection(imol, "//A/66")
    coot.set_user_defined_atom_colour_by_selection_py(chrom_imol, [("//A/66", 62)])
    coot.add_molecular_representation_py(chrom_imol, "//A/66", "userDefined", "Bonds", secondary_structure_usage_flag)
    coot.set_bond_thickness(chrom_imol, 10.0)
    
    # Center view
    coot.set_go_to_atom_chain_residue_atom_name("A", 100, "CA")
    coot.set_zoom(200)
    
    return f"Figure created: {len(strand_selections)} strands, {len(helix_selections)} helices, chromophore"

# To use (must be called with run_python after defining with run_python_multiline):
make_gfp_figure()
```

## Color Scheme Suggestions

### Standard Secondary Structure
- **Beta strands**: Blue `[0.3, 0.6, 1.0]`
- **Alpha helices**: Red/Purple `[0.8, 0.2, 0.4]` or `[0.5, 0.3, 0.5]`
- **Loops**: Gray (or leave uncolored)

### Highlight Schemes
- **Active site**: Bright orange `[1.0, 0.5, 0.0]`
- **Substrate binding**: Yellow `[1.0, 0.9, 0.0]`
- **Metal coordination**: Cyan `[0.0, 0.8, 0.8]`
- **Mutation sites**: Magenta `[1.0, 0.0, 1.0]`

### Domain Coloring
- **Domain 1**: Blue `[0.2, 0.4, 0.8]`
- **Domain 2**: Green `[0.2, 0.8, 0.4]`
- **Domain 3**: Orange `[0.9, 0.5, 0.2]`
- **Linker**: Gray `[0.6, 0.6, 0.6]`

## Troubleshooting

### Colors Don't Appear
**Problem**: Ribbon is gray after setting colors.

**Solution**: Make sure you call `add_ribbon_representation_with_user_defined_colours()` AFTER setting colors.

### Colors Disappear After Update
**Problem**: Added new colored region, but existing colors turned red/brown.

**Solution**: When recreating ribbon, reassign ALL color selections, not just new ones.

### Python Interpreter Crashes
**Problem**: Multi-line code causes "Failed to get __main__ module" error.

**Solution**: Always use function wrappers with `run_python_multiline()` then call with `run_python()`.

### Feature Not Visible
**Problem**: Extracted feature (ligand, chromophore) doesn't show up.

**Solution**: 
1. Check molecule is valid: `coot.is_valid_model_molecule(feature_imol)`
2. Ensure `add_molecular_representation_py()` succeeded
3. Verify feature molecule is displayed: `coot.set_mol_displayed(feature_imol, 1)`

## Graphics Quality Settings for Publication Figures

For publication-quality figures, especially for journal covers or high-impact visualizations, use these graphics settings:

### Background Color

Set an appropriate background color for your publication medium:

```python
# Light grey (80%) - excellent for print publications
coot.set_background_colour(0.8, 0.8, 0.8)

# Near-white (98%) - for very light backgrounds
coot.set_background_colour(0.98, 0.98, 0.98)

# Medium grey (50%) - good general purpose
coot.set_background_colour(0.5, 0.5, 0.5)

# White - for manuscripts requiring white backgrounds
coot.set_background_colour(1.0, 1.0, 1.0)

# Black - for dark backgrounds (presentations)
coot.set_background_colour(0.0, 0.0, 0.0)
```

### Outline Mode

Enable outline mode (also called "cel shading" or "toon shading") for a polished, professional look with dark edges around ribbons and bonds:

```python
# Enable outline mode
coot.set_use_outline(1)

# Disable outline mode
coot.set_use_outline(0)

# Query outline state
state = coot.use_outline_state()
```

### Fancy Graphics Mode

Enable advanced rendering effects for high-quality figures:

```python
def enable_fancy_graphics():
    """Enable all fancy graphics effects for publication figures"""
    
    # Ambient Occlusion (SSAO) - adds subtle shadows in crevices
    # Makes surfaces appear more 3D with depth perception
    coot.set_use_ambient_occlusion(1)
    
    # Fancy Lighting - enhanced lighting model
    # Provides better shading and highlights
    coot.set_use_fancy_lighting(1)
    
    # Depth Blur - depth of field effect
    # Blurs distant objects for focus effect
    coot.set_use_depth_blur(1)
    
    return "Fancy graphics enabled"

def disable_fancy_graphics():
    """Disable fancy graphics for faster rendering"""
    coot.set_use_ambient_occlusion(0)
    coot.set_use_fancy_lighting(0)
    coot.set_use_depth_blur(0)
    return "Fancy graphics disabled"
```

### SSAO Fine-Tuning

Ambient occlusion can be fine-tuned for different effects:

```python
# Adjust SSAO strength (default: typically around 1.0)
coot.set_ssao_strength(1.5)  # Stronger shadows

# Adjust SSAO radius (default: typically around 0.5)
coot.set_ssao_radius(0.7)  # Larger shadow radius

# Adjust SSAO bias (default: typically around 0.025)
coot.set_ssao_bias(0.03)  # Reduces shadow artifacts

# Set number of samples for SSAO (more = better quality, slower)
coot.set_ssao_kernel_n_samples(32)  # Default is often 16

# Set blur size (0, 1, or 2)
coot.set_ssao_blur_size(1)  # Smooths out SSAO shadows
```

### Shadow Settings

Coot provides real-time shadow rendering that adds depth and dimensionality to molecular structures:

```python
# Enable shadows by setting shadow strength (0 = off, higher = darker)
# Recommended range: 0.3-0.7
coot.set_shadow_strength(0.3)  # Subtle shadows (recommended)
coot.set_shadow_strength(0.5)  # Medium shadows
coot.set_shadow_strength(0.7)  # Strong shadows

# Shadow resolution (1-4, higher = sharper shadows)
# 4 is maximum quality
coot.set_shadow_resolution(4)  # Maximum resolution - sharpest shadows

# Shadow softness (1-3, higher = softer edges)
# 3 is maximum softness
coot.set_shadow_softness(3)  # Maximum softness - smoothest shadow edges

# Shadow box size (default: 66)
# Adjust if shadows are cut off
coot.set_shadow_box_size(66)
```

**Recommended shadow settings for publication:**
- **Strength**: 0.3 (subtle, doesn't overpower the structure)
- **Resolution**: 4 (maximum quality)
- **Softness**: 3 (smooth, professional appearance)

**When to use shadows:**
- Publication figures with complex 3D structures
- Presentations where depth perception is important
- Visualizations that benefit from enhanced spatial relationships
- Combined with mid-grey backgrounds for best effect

**Example:**
```python
def enable_publication_shadows():
    """Enable subtle, high-quality shadows for publication figures"""
    coot.set_shadow_strength(0.3)      # Subtle shadows
    coot.set_shadow_resolution(4)      # Maximum resolution
    coot.set_shadow_softness(3)        # Maximum softness
    return "Publication shadows enabled"

def disable_shadows():
    """Disable shadows"""
    coot.set_shadow_strength(0.0)
    return "Shadows disabled"
```

### Other Quality Settings

```python
# Anti-aliasing - smooths jagged edges
# Note: May need to restart Coot for this to take effect
coot.set_anti_aliasing(1)

# Enable fog for atmospheric depth
coot.set_use_fog(1)

# Perspective projection (more realistic depth)
coot.set_use_perspective_projection(1)
```

### Complete Publication Setup Example

```python
def setup_publication_graphics():
    """
    Configure Coot for creating publication-quality figures
    Optimized for journal covers and high-impact visualizations
    """
    
    # Background: 80% grey (excellent for print)
    coot.set_background_colour(0.8, 0.8, 0.8)
    
    # Enable outline mode for polished look
    coot.set_use_outline(1)
    
    # Enable all fancy graphics effects
    coot.set_use_ambient_occlusion(1)
    coot.set_use_fancy_lighting(1)
    coot.set_use_depth_blur(1)
    
    # Fine-tune SSAO for publication quality
    coot.set_ssao_strength(1.2)
    coot.set_ssao_radius(0.6)
    coot.set_ssao_kernel_n_samples(32)
    coot.set_ssao_blur_size(1)
    
    # Enable subtle, high-quality shadows
    coot.set_shadow_strength(0.3)
    coot.set_shadow_resolution(4)
    coot.set_shadow_softness(3)
    
    return "Publication graphics settings applied"

def setup_presentation_graphics():
    """
    Configure Coot for presentation slides (dark background)
    """
    
    # Black background for presentations
    coot.set_background_colour(0.0, 0.0, 0.0)
    
    # Enable outline mode
    coot.set_use_outline(1)
    
    # Enable fancy graphics
    coot.set_use_ambient_occlusion(1)
    coot.set_use_fancy_lighting(1)
    coot.set_use_depth_blur(1)
    
    # Enable shadows for presentations
    coot.set_shadow_strength(0.4)  # Slightly stronger for dark backgrounds
    coot.set_shadow_resolution(4)
    coot.set_shadow_softness(3)
    
    return "Presentation graphics settings applied"
```

## Goodsell-Style Figures

Goodsell-style figures use ball-and-stick representations with flat matte shading, outlines, and chain-based colouring. They are **not** Gaussian/molecular surfaces — the key characteristic is the illustrated, hand-drawn look achieved through specific shader settings.

### Installing the Goodsell Extension via Curlew

The Goodsell style is provided by a Curlew extension. Install it once per session:

```python
def install_goodsell_extension():
    # List available extensions to confirm it's there
    exts = coot.curlew_get_extension_list()
    for name, fname in exts:
        print(f"{name}: {fname}")
    # Install
    result = coot.curlew_download_and_install_extension("coot_goodsell_menu.py")
    print(f"Install result: {result}")  # 1 = success
    return result

install_goodsell_extension()
```

This installs two functions into the global namespace:
- `goodsell_setting()` — applies all shader/material settings (uses active atom's molecule)
- `goodsell_colour_scheme(mode)` — sets chain colouring + calls `goodsell_setting()`

### Applying Goodsell Style

```python
def apply_goodsell(imol):
    # Navigate to a residue in the target molecule to make it active
    # (goodsell_colour_scheme uses active_residue_py() to get imol)
    coot.set_go_to_atom_chain_residue_atom_name("A", 100, " CA ")

    # Choose colour wheel step mode:
    #   mode 1: step 0.221 — large steps, most distinct colours (best for hexamers etc.)
    #   mode 2: step 0.09  — medium steps, analogous palette
    #   mode 3: step 0.04  — small steps, very similar hues
    goodsell_colour_scheme(1)

    # CRITICAL: restore rotation centre after set_go_to_atom_chain_residue_atom_name
    # which moves the view to that atom as a side effect
    cx = coot.molecule_centre_internal(imol, 0)
    cy = coot.molecule_centre_internal(imol, 1)
    cz = coot.molecule_centre_internal(imol, 2)
    coot.set_rotation_centre(cx, cy, cz)

    coot.graphics_draw()
    return "Goodsell applied"

apply_goodsell(3)
```

### CRITICAL: Recentre After Navigation

`set_go_to_atom_chain_residue_atom_name()` moves the rotation centre to that atom as a side effect. **Always restore the rotation centre** to the molecule centroid immediately after:

```python
# ❌ BAD - leaves view centred on a random atom
coot.set_go_to_atom_chain_residue_atom_name("A", 100, " CA ")
goodsell_colour_scheme(1)

# ✅ GOOD - restore centre after
coot.set_go_to_atom_chain_residue_atom_name("A", 100, " CA ")
goodsell_colour_scheme(1)
cx = coot.molecule_centre_internal(imol, 0)
cy = coot.molecule_centre_internal(imol, 1)
cz = coot.molecule_centre_internal(imol, 2)
coot.set_rotation_centre(cx, cy, cz)
```

### What goodsell_setting() Does

For reference, the extension applies these settings:

```python
coot.set_background_colour(1.0, 1.0, 1.0)       # White background
coot.set_bond_smoothness_factor(3)               # Smooth bonds
coot.set_model_molecule_representation_style(imol, 1)  # Ball-and-stick
coot.set_model_material_diffuse(imol, 0.00, 0.00, 0.00, 1)  # Flat/matte
coot.set_model_material_specular(imol, 0.0, 64)  # No specular highlights
coot.set_model_material_ambient(imol, 0.5, 0.5, 0.5, 1)
coot.set_use_outline(1)                          # Dark outlines - essential
coot.set_effects_shader_brightness(1.11)         # Base brightness
coot.set_effects_shader_gamma(0.66)              # Gamma correction
coot.set_ssao_strength(0.25)                     # Subtle ambient occlusion
coot.set_use_fancy_lighting(1)
```

### Brightness Adjustment

The default brightness of 1.11 is a good starting point but often benefits from a small increase:

```python
# Default from goodsell_setting(): 1.11
# Recommended slight increase for a brighter, more vibrant result:
coot.set_effects_shader_brightness(1.22)
coot.graphics_draw()
```

**Always nudge brightness up slightly** from the default 1.11 — 1.22 has been found to give a better result.

### Screendumps

When saving screendumps, **do not specify a directory** — write to the current working directory only:

```python
# ✅ CORRECT - filename only
coot.screendump_tga("6v2f_goodsell.tga")

# ❌ WRONG - do not specify a path
coot.screendump_tga("/tmp/6v2f_goodsell.tga")
```

### Complete Goodsell Figure Workflow

```python
def make_goodsell_figure(imol, anchor_chain, anchor_resno, zoom=350):
    """
    Apply Goodsell style to imol and save a screendump.
    anchor_chain/resno: any residue in imol (used to set active atom).
    """
    # 1. Ensure bond representation is visible
    coot.set_mol_displayed(imol, 1)

    # 2. Navigate to set active atom (required by goodsell_colour_scheme)
    coot.set_go_to_atom_chain_residue_atom_name(anchor_chain, anchor_resno, " CA ")

    # 3. Apply Goodsell colouring and shader settings
    goodsell_colour_scheme(1)  # mode 1 = most distinct chain colours

    # 4. Nudge brightness above the default 1.11
    coot.set_effects_shader_brightness(1.22)

    # 5. Restore rotation centre to molecule centroid
    cx = coot.molecule_centre_internal(imol, 0)
    cy = coot.molecule_centre_internal(imol, 1)
    cz = coot.molecule_centre_internal(imol, 2)
    coot.set_rotation_centre(cx, cy, cz)

    # 6. Set zoom
    coot.set_zoom(zoom)
    coot.graphics_draw()

    # 7. Save screendump - filename only, no directory
    coot.screendump_tga("goodsell_figure.tga")

    return "Goodsell figure saved"

make_goodsell_figure(3, "A", 100, zoom=350)
```

## Summary

1. **Always use function wrappers** for complex code
2. **Set colors BEFORE creating representations**
3. **Reassign ALL colors** when recreating ribbons
4. **Use PDB header secondary structure** as the authoritative source
5. **Extract features to separate molecules** for emphasis
6. **Use consistent color schemes** for clarity
7. **Enable fancy graphics** for publication-quality figures
8. **Configure shadows** for enhanced depth (strength 0.3, resolution 4, softness 3)
9. **Choose appropriate background** for your publication medium (mid-grey works well with shadows)

Following these practices ensures reliable, publication-quality molecular graphics figures in Coot.

## Summary of Additions to coot-figure-making/SKILL.md

The following new content has been added to the figure-making skill based on today's session visualizing the 1ej6 reovirus core assembly.

---

## New Sections Added

### 1. Gaussian Surface Representations

**Key Topics Covered:**
- Creating Gaussian surfaces
- **CRITICAL RULE: Always use molecular symmetry coloring when applicable**
- Gaussian surface parameters (contour level, sigma, grid scale, box radius, B-factor)
- Working with generic display objects to selectively hide surfaces
- Downloading biological assemblies from PDBe

**Critical Best Practice:**
```python
# ALWAYS set molecular symmetry coloring for structures with symmetry
coot.set_gaussian_surface_chain_colour_mode(2)
coot.gaussian_surface(imol)
```

### 2. Downloading Biological Assemblies from PDBe

**Correct URL Format:**
- Use **hyphen** not underscore: `1ej6-assembly1` NOT `1ej6_assembly-1`
- File is **gzipped**: `.cif.gz` extension
- Base URL: `https://www.ebi.ac.uk/pdbe/static/entry/download/`

**Complete example code provided** for downloading, decompressing, and loading assemblies.

### 3. Advanced Graphics Settings for Gaussian Surfaces

**Publication-Quality SSAO Settings:**
- **256-512 kernel samples** for screenshots (not default 32)
- **Large radius (20-25)** for large assemblies
- Complete optimized settings for publication figures

**CRITICAL Discovery: Outline and Depth Blur Are Mutually Exclusive**
- Despite API allowing both, shader implementation makes them exclusive
- **Recommendation:** Use outline mode for Gaussian surfaces
- Clear documentation with correct/incorrect examples

### 4. Complete Publication Setup

**Optimized settings for Gaussian surface figures:**
- Dark grey background (0.2, 0.2, 0.2) or even smaller, for dramatic contrast
- Outline mode for polished cel-shaded look
- High-quality SSAO (256 samples, radius 25)
- Fancy lighting
- Complete working code example

---

## Updated Summary Section

Reorganized into three categories:

1. **Ribbon Representations** (existing best practices)
2. **Gaussian Surface Representations** (NEW - 6 best practices)
3. **General Publication Graphics** (existing, refined)

---

## Key Lessons Learned

### Image-Making Rules
1. **Always use molecular symmetry coloring** for structures with symmetry
2. **Use 256-512 SSAO kernel samples** for publication screenshots
3. **Outline and depth blur are mutually exclusive** in the shader
4. **Large SSAO radius (20-25)** needed for large assemblies
5. **Correct PDBe assembly URL format** with hyphen and .cif.gz

### Why This Matters
- Molecular symmetry coloring **immediately reveals biological organization**
- High kernel samples produce **smooth, professional shadows** with low levels of ambient occlusion sampling noise
- Large assemblies need different parameters than small molecules
- Biological assemblies show the **true functional form** of the structure

---

## Code Examples Added

1. Download biological assembly from PDBe
2. Hide first half of generic display objects
3. Setup publication-quality SSAO for Gaussian surfaces
4. Complete publication graphics configuration
5. All with proper error handling and documentation

---

## Session Context

These updates came from successfully:
1. Fetching PDB 1ej6 (reovirus core, 300-chain assembly)
2. Downloading biological assembly via PDBe API
3. Creating Gaussian surface with molecular symmetry coloring
4. Optimizing graphics settings for publication quality
5. Discovering shader limitations (outline/depth blur exclusivity)
6. Finding optimal SSAO parameters through experimentation

The result: A beautiful visualization of icosahedral viral symmetry with 5 colors showing the distribution of 5 unique chain types across 300 chains in the biological assembly.

