KLayout is a high performance layout viewer and editor that supports GDS and OASIS files and more formats
—
GUI components for layout visualization, user interaction, layer management, and display customization when running in GUI mode with Qt support.
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."""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."""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.)
"""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."""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."""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")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")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")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 loopimport 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