Interactive Controls



apply_command

apply_command(command: str) -> 'Gw

Apply a GW command string.

Parameters:

  • command (str): GW command to execute (e.g., “filter”, “count”, etc.)

key_press

key_press(key: int, scancode: int, action: int, mods: int) -> None

Process a key press event.

Parameters:

  • key (int): Key code
  • scancode (int): Scan code
  • action (int): Key action code
  • mods (int): Modifier keys

mouse_event

mouse_event(x_pos: float, y_pos: float, button: int, action: int) -> None

Process a mouse event.

Parameters:

  • x_pos (float): Mouse x-position
  • y_pos (float): Mouse y-position
  • button (int): Mouse button code (can be “left”, “right”)
  • action (int): Mouse action code

flush_log

flush_log() -> str

Returns and clears the GW log. This is useful for retrieving messages generated by GW during operation.

Returns:

  • str: GW log as a python string

Example:

# Get any messages from GW
log_messages = gw.flush_log()
print(log_messages)

set_active_region_index

set_active_region_index(index: int) -> 'Gw'

Set the currently active region for visualisation. Subsequent mouse/key interactions will affect this region index.

Parameters:

  • index (int): Index of the region to activate

Returns:

  • Gw: Self for method chaining

clear_buffer

clear_buffer -> bool

Property that indicates whether the read buffer should be cleared on the next draw.

Returns:

  • bool: Read buffer needs clearing

Example:

# Check if buffer needs clearing
if gw.clear_buffer:
    print("Buffer will be cleared on next draw")

set_clear_buffer

set_clear_buffer(state: bool) -> None

Set the clear_buffer status.

Parameters:

  • state (bool): If True, buffer will be cleared on next draw

Example:

# Force buffer clearing on next draw
gw.set_clear_buffer(True)

redraw

redraw -> bool

Property that indicates whether a re-draw needs to occur. Check this after some event e.g. command or mouse button.

Returns:

  • bool: Image needs to be re-drawn

Example:

# Check if a redraw is needed
if gw.redraw:
    gw.draw()

set_redraw

set_redraw(state: bool) -> None

Set the redraw status. For dynamic applications, set this to False after a drawing call to avoid unnecessary redraws.

Parameters:

  • state (bool): If True, a redraw will be triggered

Example:

# Set redraw status
gw.set_redraw(False)  # Prevent automatic redraw

Interactive Application Development

Creating interactive applications with gwplot involves managing drawing states, handling user interactions, and efficiently updating the visualization. Here’s a practical approach based on real-world usage:

from gwplot import Gw, GLFW
from flask import Flask, request, jsonify, send_file
import io

# Initialize Gw with a reference genome
gw = Gw("hg38", canvas_width=1200, canvas_height=800)
gw.add_bam("sample.bam")
gw.add_region("chr1", 1000000, 1100000)

# Handle mouse events
def handle_mouse_interaction(x_pos, y_pos, button, action):
    # Convert button names to constants if needed
    button_code = GLFW.MOUSE_BUTTON_LEFT if button == "left" else GLFW.MOUSE_BUTTON_RIGHT
    action_code = GLFW.PRESS if action == "press" else GLFW.RELEASE
    
    # Process the mouse event
    gw.mouse_event(x_pos, y_pos, button_code, action_code)
    
    # Check if we need to redraw
    if gw.redraw:
        gw.draw()
        return True
    return False

# Handle keyboard interactions
def handle_key_press(key):
    # Map keys to GLFW constants
    key_mapping = {
        'ArrowRight': GLFW.KEY_RIGHT,
        'ArrowLeft': GLFW.KEY_LEFT,
        'ArrowUp': GLFW.KEY_UP,
        'ArrowDown': GLFW.KEY_DOWN,
    }
    
    if key in key_mapping:
        key_code = key_mapping[key]
        scancode = GLFW.get_key_scancode(key_code)
        gw.key_press(key_code, scancode, GLFW.PRESS, 0)
        
        # Check if we need to redraw
        if gw.redraw:
            gw.draw()
            return True
    return False

# Handle command input
def handle_command(cmd_text):
    gw.apply_command(cmd_text)
    
    # Get any log output from the command
    log_output = gw.flush_log()
    
    # Check if we need to redraw or clear buffer
    needs_redraw = gw.redraw
    needs_clear = gw.clear_buffer
    
    if needs_redraw:
        gw.draw(clear_buffer=needs_clear)
        return True, log_output
    return False, log_output

# Get image data for display
def get_image_data():
    # Encode as PNG (higher quality but larger size)
    img_data = gw.encode_as_png()
    
    # Alternative: faster but lower quality
    # img_data = gw.encode_as_jpeg(quality=80)
    
    return img_data

Web Application Integration

The above functions can be integrated into a web framework like Flask to create interactive browser-based applications:

app = Flask(__name__)

@app.route('/display_image')
def display_image():
    gw.draw()  # Ensure the latest state is drawn
    img_data = gw.encode_as_png()
    img_io = io.BytesIO(img_data)
    img_io.seek(0)
    return send_file(img_io, mimetype='image/png')

@app.route('/mouse-event', methods=['POST'])
def mouse_event():
    data = request.get_json()
    x_pos = data.get('x')
    y_pos = data.get('y')
    button = data.get('button')  # "left" or "right"
    action = data.get('action')  # "press" or "release"
    
    needs_redraw = handle_mouse_interaction(x_pos, y_pos, button, action)
    
    if needs_redraw:
        return display_image()
    return jsonify({'success': True})

@app.route('/key-event', methods=['POST'])
def key_event():
    data = request.get_json()
    key = data.get('key')
    
    needs_redraw = handle_key_press(key)
    
    if needs_redraw:
        return display_image()
    return jsonify({'success': True})

@app.route('/submit', methods=['POST'])
def submit():
    command = request.form['command']
    needs_redraw, log = handle_command(command)
    
    if needs_redraw:
        return display_image()
    return jsonify({'success': True, 'log': log})

Key Concepts for Interactive Applications

  1. State Tracking:
    • Use gw.redraw to check if visualization needs updating
    • Use gw.clear_buffer to check if read buffer needs clearing
  2. Event Handling:
    • Map UI events to appropriate mouse_event and key_press calls
    • Properly manage button and action states
  3. Command Processing:
    • Use apply_command() to execute user commands
    • Retrieve command output with flush_log()
  4. Responsive Rendering:
    • Only redraw when necessary to improve performance
    • Adjust canvas size based on viewport/display
  5. Multi-User Support:
    • Create separate Gw instances for each user session
    • Manage session lifecycle (creation, updates, cleanup)

A complete example implementing these concepts can be found in the repository at examples/flask_demo/flask_server.py.