CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-klayout

KLayout is a high performance layout viewer and editor that supports GDS and OASIS files and more formats

Pending
Overview
Eval results
Files

layout-viewer.mddocs/

Layout Viewer and GUI Components

GUI components for layout visualization, user interaction, layer management, and display customization when running in GUI mode with Qt support.

Capabilities

Layout Viewing

class LayoutView:
    def __init__(self):
        """Create a new layout view widget."""
    
    def load_layout(self, layout: Layout, add_cellview: bool = True) -> int:
        """
        Load a layout into the view.
        
        Parameters:
        - layout: Layout object to display
        - add_cellview: Whether to add a cellview for this layout
        
        Returns:
        int: Cellview index
        """
    
    def create_layout(self, add_cellview: bool = True) -> int:
        """
        Create a new empty layout in the view.
        
        Returns:
        int: Cellview index
        """
    
    def active_cellview_index(self) -> int:
        """Get the index of the currently active cellview."""
    
    def set_active_cellview_index(self, index: int) -> None:
        """Set the active cellview by index."""
    
    def cellview(self, index: int) -> CellView:
        """Get cellview by index."""
    
    def zoom_fit(self) -> None:
        """Zoom to fit all visible content."""
    
    def zoom_box(self, bbox: DBox) -> None:
        """
        Zoom to specific bounding box.
        
        Parameters:
        - bbox: Bounding box to zoom to
        """
    
    def pan_center(self, center: DPoint) -> None:
        """
        Pan view to center on specified point.
        
        Parameters:
        - center: Point to center the view on
        """
    
    def set_config(self, config_name: str, config_value: str) -> None:
        """Set configuration parameter."""
    
    def get_config(self, config_name: str) -> str:
        """Get configuration parameter value."""

class CellView:
    def __init__(self, layout: Layout = None):
        """
        Create a cellview for a layout.
        
        Parameters:
        - layout: Layout to view (optional)
        """
    
    @property
    def layout(self) -> Layout:
        """Get the associated layout."""
    
    @property
    def cell_index(self) -> int:
        """Get the current top cell index."""
    
    def set_cell(self, cell_index: int) -> None:
        """
        Set the top cell to display.
        
        Parameters:
        - cell_index: Index of cell to display
        """
    
    @property
    def name(self) -> str:
        """Get cellview name."""
    
    def set_name(self, name: str) -> None:
        """Set cellview name."""
    
    def is_valid(self) -> bool:
        """Check if cellview is valid."""
    
    def close(self) -> None:
        """Close the cellview."""

Layer Management and Display

class LayerPropertiesNode:
    def __init__(self):
        """Create a layer properties node."""
    
    def source_layer_info(self) -> LayerInfo:
        """Get source layer information."""
    
    def set_source_layer_info(self, layer_info: LayerInfo) -> None:
        """Set source layer information."""
    
    @property
    def name(self) -> str:
        """Get layer name."""
    
    def set_name(self, name: str) -> None:
        """Set layer name."""
    
    @property
    def visible(self) -> bool:
        """Check if layer is visible."""
    
    def set_visible(self, visible: bool) -> None:
        """Set layer visibility."""
    
    @property
    def transparent(self) -> bool:
        """Check if layer is transparent."""
    
    def set_transparent(self, transparent: bool) -> None:
        """Set layer transparency."""
    
    @property
    def width(self) -> int:
        """Get line width for layer display."""
    
    def set_width(self, width: int) -> None:
        """Set line width for layer display."""
    
    def fill_color(self) -> int:
        """Get fill color (RGB)."""
    
    def set_fill_color(self, color: int) -> None:
        """Set fill color (RGB value)."""
    
    def frame_color(self) -> int:
        """Get frame/outline color."""
    
    def set_frame_color(self, color: int) -> None:
        """Set frame/outline color."""

class LayerPropertiesList:
    def __init__(self):
        """Create layer properties list."""
    
    def append(self, properties: LayerPropertiesNode) -> None:
        """Add layer properties to list."""
    
    def insert(self, index: int, properties: LayerPropertiesNode) -> None:
        """Insert layer properties at specific index."""
    
    def erase(self, index: int) -> None:
        """Remove layer properties at index."""
    
    def clear(self) -> None:
        """Clear all layer properties."""
    
    def size(self) -> int:
        """Get number of layer properties."""
    
    def __getitem__(self, index: int) -> LayerPropertiesNode:
        """Get layer properties by index."""

Annotations and Markers

class Annotation:
    def __init__(self):
        """Create an annotation object."""
    
    @property
    def id(self) -> int:
        """Get annotation ID."""
    
    def set_text(self, text: str) -> None:
        """
        Set annotation text.
        
        Parameters:
        - text: Text to display
        """
    
    def text(self) -> str:
        """Get annotation text."""
    
    def set_position(self, position: DPoint) -> None:
        """Set annotation position."""
    
    def position(self) -> DPoint:
        """Get annotation position."""
    
    def set_color(self, color: int) -> None:
        """Set annotation color."""
    
    def color(self) -> int:
        """Get annotation color."""
    
    def set_outline_color(self, color: int) -> None:
        """Set outline color."""
    
    def outline_color(self) -> int:
        """Get outline color."""

class Marker:
    def __init__(self):
        """Create a marker for highlighting areas."""
    
    def set_color(self, color: int) -> None:
        """Set marker color."""
    
    def color(self) -> int:
        """Get marker color."""
    
    def set_vertex_size(self, size: int) -> None:
        """Set vertex marker size."""
    
    def vertex_size(self) -> int:
        """Get vertex marker size."""
    
    def set_line_width(self, width: int) -> None:
        """Set line width for marker."""
    
    def line_width(self) -> int:
        """Get marker line width."""
    
    def set(self, shape) -> None:
        """
        Set marker to highlight a shape.
        
        Parameters:
        - shape: Shape to highlight (Box, Polygon, etc.)
        """

Display State Management

class DisplayState:
    def __init__(self):
        """Create display state manager."""
    
    def visible_layers(self) -> list[int]:
        """Get list of visible layer indices."""
    
    def set_layer_visible(self, layer: int, visible: bool) -> None:
        """
        Set layer visibility.
        
        Parameters:
        - layer: Layer index
        - visible: Visibility state
        """
    
    def layer_visible(self, layer: int) -> bool:
        """Check if layer is visible."""
    
    def set_color(self, layer: int, color: int) -> None:
        """Set layer display color."""
    
    def color(self, layer: int) -> int:
        """Get layer display color."""

class ViewObject:
    def __init__(self):
        """Generic view object for custom display elements."""
    
    def bbox(self) -> DBox:
        """Get bounding box of the view object."""
    
    def set_visible(self, visible: bool) -> None:
        """Set object visibility."""
    
    def visible(self) -> bool:
        """Check if object is visible."""

GUI Utility Functions

def has_gui() -> bool:
    """
    Check if GUI functionality is available.
    
    Returns:
    bool: True if GUI is available (Qt is loaded)
    """

def can_create_layoutview() -> bool:
    """
    Check if LayoutView can be created.
    
    Returns:
    bool: True if LayoutView creation is supported
    """

class Application:
    @staticmethod
    def instance() -> Application:
        """Get the application instance."""
    
    def main_window(self):
        """Get the main application window."""
    
    def set_config(self, key: str, value: str) -> None:
        """Set application configuration value."""
    
    def get_config(self, key: str) -> str:
        """Get application configuration value."""
    
    def exec_() -> int:
        """Run the application event loop."""

Usage Examples

Basic Layout Viewing

import klayout.db as db
import klayout.lay as lay

# Check if GUI is available
if not lay.has_gui():
    print("GUI not available - running in headless mode")
    exit()

# Create layout with some content
layout = db.Layout()
top_cell = layout.create_cell("TOP")

# Add some shapes
layer1 = layout.layer(db.LayerInfo(1, 0))
layer2 = layout.layer(db.LayerInfo(2, 0))

top_cell.shapes(layer1).insert(db.Box(0, 0, 1000, 1000))
top_cell.shapes(layer2).insert(db.Box(200, 200, 800, 800))

# Create and configure layout view
if lay.can_create_layoutview():
    view = lay.LayoutView()
    
    # Load layout into view
    cellview_index = view.load_layout(layout)
    
    # Set the top cell
    cellview = view.cellview(cellview_index)
    cellview.set_cell(top_cell.cell_index)
    
    # Zoom to fit content
    view.zoom_fit()
    
    print("Layout loaded in viewer")

Layer Display Configuration

import klayout.db as db
import klayout.lay as lay

layout = db.Layout()
layout.read("complex_design.gds")

if lay.can_create_layoutview():
    view = lay.LayoutView()
    cellview_index = view.load_layout(layout)
    
    # Configure layer display properties
    layer_props_list = lay.LayerPropertiesList()
    
    # Metal 1 - Blue fill, solid
    metal1_props = lay.LayerPropertiesNode()
    metal1_props.set_source_layer_info(db.LayerInfo(1, 0))
    metal1_props.set_name("METAL1")
    metal1_props.set_fill_color(0x0000FF)  # Blue
    metal1_props.set_frame_color(0x000080) # Dark blue outline
    metal1_props.set_visible(True)
    metal1_props.set_transparent(False)
    metal1_props.set_width(1)
    layer_props_list.append(metal1_props)
    
    # Metal 2 - Red fill, transparent
    metal2_props = lay.LayerPropertiesNode()
    metal2_props.set_source_layer_info(db.LayerInfo(2, 0))
    metal2_props.set_name("METAL2")
    metal2_props.set_fill_color(0xFF0000)  # Red
    metal2_props.set_frame_color(0x800000) # Dark red outline
    metal2_props.set_visible(True)
    metal2_props.set_transparent(True)
    metal2_props.set_width(2)
    layer_props_list.append(metal2_props)
    
    # Via - Green outline only
    via_props = lay.LayerPropertiesNode()
    via_props.set_source_layer_info(db.LayerInfo(3, 0))
    via_props.set_name("VIA")
    via_props.set_fill_color(0x00FF00)    # Green (not used for outline-only)
    via_props.set_frame_color(0x00FF00)   # Green outline
    via_props.set_visible(True)
    via_props.set_transparent(True)       # Transparent fill
    via_props.set_width(3)
    layer_props_list.append(via_props)
    
    print(f"Configured {layer_props_list.size()} layer display properties")

Adding Annotations and Markers

import klayout.db as db
import klayout.lay as lay

layout = db.Layout()
layout.read("design_with_issues.gds")

if lay.can_create_layoutview():
    view = lay.LayoutView()
    cellview_index = view.load_layout(layout)
    
    # Add annotations for important features
    annotation1 = lay.Annotation()
    annotation1.set_text("Critical timing path")
    annotation1.set_position(db.DPoint(100.5, 200.5))
    annotation1.set_color(0xFF0000)  # Red text
    annotation1.set_outline_color(0x800000)  # Dark red outline
    
    annotation2 = lay.Annotation()
    annotation2.set_text("Power distribution node")
    annotation2.set_position(db.DPoint(500.0, 300.0))
    annotation2.set_color(0x0000FF)  # Blue text
    
    # Create markers for highlighting specific areas
    marker1 = lay.Marker()
    marker1.set_color(0xFFFF00)  # Yellow
    marker1.set_line_width(3)
    marker1.set_vertex_size(10)
    
    # Highlight a specific polygon (e.g., design rule violation)
    violation_area = db.Box(150, 150, 200, 200)
    marker1.set(violation_area)
    
    marker2 = lay.Marker()
    marker2.set_color(0xFF00FF)  # Magenta
    marker2.set_line_width(2)
    
    # Highlight another area
    critical_path = db.Path([db.Point(0, 100), db.Point(500, 100), 
                            db.Point(500, 400)], 10)
    marker2.set(critical_path.polygon())
    
    print("Added annotations and markers to highlight design features")

Interactive View Control

import klayout.db as db
import klayout.lay as lay

def setup_interactive_view(layout_file: str):
    """Set up an interactive layout view with custom controls."""
    
    if not lay.has_gui():
        print("GUI not available")
        return None
        
    layout = db.Layout()
    layout.read(layout_file)
    
    view = lay.LayoutView()
    cellview_index = view.load_layout(layout)
    
    # Configure view settings
    view.set_config("grid-visible", "true")
    view.set_config("grid-color", "#808080")
    view.set_config("background-color", "#000000")  # Black background
    view.set_config("text-visible", "true")
    
    # Set up zoom and pan shortcuts
    bbox = layout.top_cell().bbox_per_layer(layout.layer(db.LayerInfo(1, 0)))
    if not bbox.empty():
        # Convert to double precision for view
        dbbox = db.DBox(bbox.left, bbox.bottom, bbox.right, bbox.top)
        view.zoom_box(dbbox)
    
    # Pan to interesting area
    center = db.DPoint(500.0, 500.0)  # Adjust based on your design
    view.pan_center(center)
    
    return view

def create_custom_layer_setup(view: lay.LayoutView, layout: db.Layout):
    """Create a custom layer display setup."""
    
    # Define layer colors and properties
    layer_configs = [
        {"layer": (1, 0), "name": "NWELL", "color": 0x80FF80, "transparent": True},
        {"layer": (2, 0), "name": "ACTIVE", "color": 0x80FFFF, "transparent": False},
        {"layer": (3, 0), "name": "POLY", "color": 0xFF8080, "transparent": False},
        {"layer": (4, 0), "name": "CONTACT", "color": 0x8080FF, "transparent": False},
        {"layer": (5, 0), "name": "METAL1", "color": 0x0080FF, "transparent": False},
        {"layer": (6, 0), "name": "VIA1", "color": 0xFF0080, "transparent": True},
        {"layer": (7, 0), "name": "METAL2", "color": 0xFF8000, "transparent": False},
    ]
    
    layer_props_list = lay.LayerPropertiesList()
    
    for config in layer_configs:
        props = lay.LayerPropertiesNode()
        layer_info = db.LayerInfo(config["layer"][0], config["layer"][1])
        
        props.set_source_layer_info(layer_info)
        props.set_name(config["name"])
        props.set_fill_color(config["color"])
        props.set_frame_color(config["color"] & 0x808080)  # Darker frame
        props.set_visible(True)
        props.set_transparent(config["transparent"])
        props.set_width(1)
        
        layer_props_list.append(props)
    
    print(f"Created custom layer setup with {len(layer_configs)} layers")
    return layer_props_list

# Example usage
if __name__ == "__main__":
    view = setup_interactive_view("my_design.gds")
    if view:
        print("Interactive view created successfully")
        
        # If running in a Qt application context
        if lay.Application.instance():
            app = lay.Application.instance()
            app.exec_()  # Start event loop

Programmatic View Navigation

import klayout.db as db
import klayout.lay as lay
import time

def tour_layout(layout_file: str):
    """Create an automated tour of a layout."""
    
    layout = db.Layout()
    layout.read(layout_file)
    
    if not lay.can_create_layoutview():
        print("Cannot create layout view")
        return
        
    view = lay.LayoutView()
    cellview_index = view.load_layout(layout)
    
    # Find interesting areas to visit
    tour_points = []
    
    # Collect bounding boxes of all cells
    for cell in layout.each_cell():
        if not cell.is_empty():
            bbox = cell.bbox()
            if not bbox.empty():
                center = db.DPoint((bbox.left + bbox.right) / 2.0,
                                 (bbox.bottom + bbox.top) / 2.0)
                # Create zoom box around center
                zoom_size = max(bbox.width(), bbox.height()) * 1.2
                zoom_box = db.DBox(center.x - zoom_size/2, center.y - zoom_size/2,
                                 center.x + zoom_size/2, center.y + zoom_size/2)
                tour_points.append((cell.name, center, zoom_box))
    
    # Tour through the points
    for cell_name, center, zoom_box in tour_points[:10]:  # Limit to first 10
        print(f"Visiting cell: {cell_name}")
        
        # Pan to center
        view.pan_center(center)
        time.sleep(1)  # Wait 1 second
        
        # Zoom to show the cell
        view.zoom_box(zoom_box)
        time.sleep(2)  # Wait 2 seconds
    
    # Return to fit view
    view.zoom_fit()
    print("Tour completed")

# Example: Analyze what's visible in current view
def analyze_visible_content(view: lay.LayoutView):
    """Analyze the content visible in the current view."""
    
    # Get current view bounds (this would require view state access)
    # This is a simplified example
    
    cellview = view.cellview(view.active_cellview_index())
    if not cellview.is_valid():
        return
        
    layout = cellview.layout
    top_cell = layout.cell(cellview.cell_index)
    
    print(f"Analyzing cell: {top_cell.name}")
    print(f"Cell has {top_cell.child_cells()} child cells")
    
    # Count shapes per layer
    layer_counts = {}
    for layer_index in range(layout.layers()):
        if layout.is_valid_layer(layer_index):
            layer_info = layout.get_info(layer_index)
            shape_count = top_cell.shapes(layer_index).size()
            if shape_count > 0:
                layer_counts[f"{layer_info.layer}/{layer_info.datatype}"] = shape_count
    
    print("Shapes per layer:")
    for layer, count in sorted(layer_counts.items()):
        print(f"  {layer}: {count} shapes")

if __name__ == "__main__":
    tour_layout("complex_design.gds")

Install with Tessl CLI

npx tessl i tessl/pypi-klayout

docs

database-operations.md

file-io.md

hierarchical-design.md

index.md

layout-viewer.md

shape-operations.md

transformations.md

verification.md

tile.json