diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 4d267a1e3d9104eb0cb3e7c43de6ae03eeb013ee..73659fe6b2241a3ec8a9a6190301d7a44bd18112 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -130,9 +130,29 @@ class Schedule:
         self._schedule_time = time
         return self
 
+    @property
+    def sfg(self) -> SFG:
+        return self._sfg
+    
+    @property
+    def start_times(self) -> Dict[GraphID, int]: 
+        return self._start_times
+    
+    @property
+    def laps(self) -> Dict[GraphID, List[int]]:
+        return self._laps
+    
     @property
     def schedule_time(self) -> int:
         return self._schedule_time
+    
+    @property
+    def cyclic(self) -> bool:
+        return self._cyclic
+    
+    @property
+    def resolution(self) -> int:
+        return self._resolution
 
     def increase_time_resolution(self, factor: int) -> "Schedule":
         raise NotImplementedError
diff --git a/b_asic/scheduler-gui/graphics_axis_item.py b/b_asic/scheduler-gui/graphics_axis_item.py
index 86c49266c5c369d024f27ca3a847de36d22ed482..3bd84fab309ceacd7ec7541e913869b50a6fd53b 100644
--- a/b_asic/scheduler-gui/graphics_axis_item.py
+++ b/b_asic/scheduler-gui/graphics_axis_item.py
@@ -46,7 +46,7 @@ class GraphicsAxisItem(QGraphicsItemGroup):
     _x_indent:  float
     _axis:      dict[str, QGraphicsItemGroup|QGraphicsLineItem]
 
-    def __init__(self, width: float = 10.0, height: float = 10.0, x_indent: float = 2.0, parent: QGraphicsItem = None):
+    def __init__(self, width: float = 1.0, height: float = 1.0, x_indent: float = 0.2, parent: QGraphicsItem = None):
         super().__init__(parent)
 
         self._dy_height = 5/self._scale
@@ -55,7 +55,7 @@ class GraphicsAxisItem(QGraphicsItemGroup):
         # self.setFlag(QGraphicsItem.ItemIsSelectable)
         # self.setAcceptHoverEvents(True)
 
-        self.update_(width*10.0 + 6, height, x_indent)
+        self.update_(width + 0.6, height, x_indent)
     
 
     @property
@@ -121,33 +121,33 @@ class GraphicsAxisItem(QGraphicsItemGroup):
         x_scale_labels = []
         x_ledger = []
         self._axis['x_ledger'] = QGraphicsItemGroup()
-        for i in range(int(self._width/10) + 1):
+        for i in range(int(self._width) + 1):
             # vertical x-scale
-            x_scale.append(QGraphicsLineItem(0, 0, 0, 0.5))
+            x_scale.append(QGraphicsLineItem(0, 0, 0, 0.05))
             x_scale[i].setPen(pen)
-            x_scale[i].setPos(self._x_indent + i*10, 0)
+            x_scale[i].setPos(self._x_indent + i, 0)
             self._axis['x'].addToGroup(x_scale[i])
             # numbers
             x_scale_labels.append(QGraphicsSimpleTextItem(str(i)))
             x_scale_labels[i].setScale(x_scale_labels[i].scale() / self._scale)
             half_width = x_scale_labels[i].boundingRect().width()/(2*self._scale)
-            x_scale_labels[i].setPos(self._x_indent + i*10 - half_width, 0.8)
+            x_scale_labels[i].setPos(self._x_indent + i - half_width, 0.08)
             self._axis['x'].addToGroup(x_scale_labels[i])
             # vertical x-ledger
             x_ledger.append(QGraphicsLineItem(0, 0, 0, self._height))
-            if i == int(self._width/10):
+            if i == int(self._width):
                 ledger_pen.setWidthF(2/self._scale)
                 ledger_pen.setStyle(Qt.DashLine)
                 ledger_pen.setColor(Qt.black)
             x_ledger[i].setPen(ledger_pen)
-            x_ledger[i].setPos(self._x_indent + i*10, 0)
+            x_ledger[i].setPos(self._x_indent + i, 0)
             self._axis['x_ledger'].addToGroup(x_ledger[i])
         # x-axis label
         label = QGraphicsSimpleTextItem('time')
         label.setScale(label.scale() / self._scale)
         half_width = label.boundingRect().width()/(2*self._scale)
         arrow_half_width = arrow_size/2
-        label.setPos(self._width - half_width + arrow_half_width, 0.8)
+        label.setPos(self._width - half_width + arrow_half_width, 0.08)
         self._axis['x'].addToGroup(label)
         self._axis['x'].boundingRect()
 
diff --git a/b_asic/scheduler-gui/graphics_component_item.py b/b_asic/scheduler-gui/graphics_component_item.py
index c0a41aeb6ba32f47a0ec3329c6176674f57694af..16003628185791131b038b0b45d603b4767fce25 100644
--- a/b_asic/scheduler-gui/graphics_component_item.py
+++ b/b_asic/scheduler-gui/graphics_component_item.py
@@ -5,7 +5,7 @@ import os
 import sys
 from typing             import Any, Optional
 from pprint             import pprint
-from typing import Any, AnyStr, Generic, Protocol, TypeVar, Union, Optional, overload, Final, final
+from typing import Any, AnyStr, Generic, Protocol, TypeVar, Union, Optional, overload, Final, final, Dict, OrderedDict
 # from typing_extensions import Self, Final, Literal, LiteralString, TypeAlias, final
 import numpy as np
 
@@ -24,7 +24,8 @@ from qtpy.QtWidgets import (
     QGraphicsView, QGraphicsScene, QGraphicsWidget,
     QGraphicsLayout, QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayoutItem, QGraphicsAnchorLayout,
     QGraphicsItem, QGraphicsItemGroup, QGraphicsPathItem, QGraphicsRectItem,
-    QStyleOptionGraphicsItem, QWidget, QGraphicsObject, QGraphicsSceneMouseEvent, QGraphicsSimpleTextItem)
+    QStyleOptionGraphicsItem, QWidget, QGraphicsObject, QGraphicsSceneMouseEvent, QGraphicsSimpleTextItem,
+    QGraphicsEllipseItem)
 from qtpy.QtCore    import (
     QPoint, QPointF)
 
@@ -39,29 +40,37 @@ class GraphicsComponentItem(QGraphicsItemGroup):
     _scale:                 float = 1.0 # static, changed from MainWindow
     _op_id:                 str
     _height:                float
+    # _input_ports_latency:   Dict[str, int]
+    # _output_ports_latency:  Dict[str, int]
+    _input_ports:           OrderedDict[str, Dict[str, int]]   # ['id']['latency/pos']
+    _output_ports:          OrderedDict[str, Dict[str, int]]
+    # _ports:                 OrderedDict[str, Dict[str, int]]
+    _execution_time:        Union[int, None]
     _component_item:        QGraphicsPathItem
     _execution_time_item:   QGraphicsPathItem
-    _text_item:             QGraphicsSimpleTextItem
+    _label_item:            QGraphicsSimpleTextItem
     _item_group:            QGraphicsItemGroup
     
     
-    def __init__(self, op_id: str, height: float = 10.0, parent: QGraphicsItem = None):
+    def __init__(self, op_id: str, latency_offsets: Dict[str, int], execution_time: Union[int, None] = None, height: float = 1.0, parent: QGraphicsItem = None):
         super().__init__(parent)
 
         self._op_id = op_id
         self._height = height
+        self._latency_offsets = latency_offsets
+        input_ports_latency = {k:v for k,v in latency_offsets.items() if k.lower().startswith("in")}
+        output_ports_latency = {k:v for k,v in latency_offsets.items() if k.lower().startswith("out")}
+        self._input_ports = {k:{'latency':v} for k,v in input_ports_latency.items()}
+        self._output_ports = {k:{'latency':v} for k,v in output_ports_latency.items()}
+        print(f'self._input_ports:  {self._input_ports}')
+        print(f'self._output_ports: {self._output_ports}')
+        self._execution_time = execution_time
         self._component_item = QGraphicsPathItem()
         self._item_group = QGraphicsItemGroup()
-        # self.setHandlesChildEvents(True)                # PySide2 QGraphicsItemGroup default: true. PyQt5 not an option
+
         self.setFlag(QGraphicsItem.ItemIsMovable)       # mouse move events
-        # self.setFlag(QGraphicsItem.ItemIsSelectable)    # mouse click events
-        # self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
-        self.setAcceptHoverEvents(True)
-        # self.setAcceptTouchEvents(True)
-        # self.setAcceptDrops(True)
-        # self.setAcceptedMouseButtons(Qt.AllButtons)
-        self.setAcceptedMouseButtons(Qt.LeftButton)
-        # self.setAcceptedMouseButtons(Qt.NoButton)
+        self.setAcceptHoverEvents(True)                 # mouse hover events
+        self.setAcceptedMouseButtons(Qt.LeftButton)     # accepted buttons for movements
         
         self._populate()
     
@@ -82,43 +91,106 @@ class GraphicsComponentItem(QGraphicsItemGroup):
         # pen.setCapStyle(Qt.RoundCap)      # Qt.FlatCap, Qt.SquareCap (default), Qt.RoundCap
         pen.setJoinStyle(Qt.RoundJoin)      # Qt.MiterJoin, Qt.BevelJoin (default), Qt.RoundJoin, Qt.SvgMiterJoin
         
-        # component path
-        component_path = QPainterPath(QPoint(0,0))
-        component_path.lineTo(0, self._height/2)
-        component_path.lineTo(2, self._height/2)
-        component_path.lineTo(2, self._height)
-        component_path.lineTo(40, self._height)
-        component_path.lineTo(40, 0)
+        ## component path
+        inport_list = list(self._input_ports)
+        output_list = list(self._output_ports)
+        output_list.reverse()
+        x = self._input_ports[inport_list[0]]['latency']
+        y = 0
+        old_x = x
+        old_y = y
+        component_path = QPainterPath(QPointF(x, y))    # start point
+        
+        # draw inport side lines
+        for i in range(len(inport_list)):
+            key = inport_list[i]
+            # draw 1 or 2 lines
+            x = self._input_ports[inport_list[i]]['latency']
+            if x != old_x:
+                component_path.lineTo(x, y)
+            y = old_y + (self._height / len(inport_list))
+            component_path.lineTo(x, y)
+            # register the port pos in dictionary
+            port_x = x
+            port_y = y - abs(y - old_y)/2   # port coord is at the center of previous line
+            self._input_ports[key]['pos'] = QPoint(port_x, port_y)
+            # update last pos
+            old_x = x
+            old_y = y
+            print(f'{key}({x}, {y})\tport({port_x}, {port_y})')
+        
+        # draw inport side lines
+        for i in range(len(output_list)):
+            key = output_list[i]
+            # draw 1 or 2 lines
+            x = self._output_ports[output_list[i]]['latency']
+            if x != old_x:
+                component_path.lineTo(x, y)
+            y = old_y - (self._height / len(output_list))
+            component_path.lineTo(x, y)
+            # register the port pos in dictionary
+            port_x = x
+            port_y = y + abs(y - old_y)/2   # port coord is at the center of previous line
+            self._output_ports[key]['pos'] = QPoint(port_x, port_y)
+            # update last pos
+            old_x = x
+            old_y = y
+            print(f'{key}({x}, {y})\tport({port_x}, {port_y})')
+            
         component_path.closeSubpath()
+        
+        ## ports item
+        pen2 = QPen(Qt.darkGray)
+        pen2.setWidthF(2/self._scale)
+        brush2 = QBrush(Qt.black)
+        port_items = []
+        for key in self._input_ports:
+            port_pos = self.mapToParent(self._input_ports[key]['pos'])
+            
+            port = QGraphicsEllipseItem(port_pos.x(), port_pos.y(), 1/self._scale, 1/self._scale)
+            port_items.append(port)
+            # port_items[-1].setPos(self._input_ports[key]['pos'])
+            # port_items[-1].setScale(0.5)
+            # port_items[-1].setPen(pen2)
+            # print(port_items[-1])
+            # port_items[-1].setBrush(brush2)
+            # port_items[-1].setPos(1, 0.5)
+            break
+
 
-        # component item
+        ## component item
         self._component_item.setPath(component_path)
         self._component_item.setPen(pen)
         self._component_item.setBrush(brush)
-        self._component_item.setPos(10, 0)      # in parent (i.e. self) coordinates
+        # self._component_item.setPos(1, 0)      # in parent (i.e. self) coordinates
 
-        # op-id/label
+        ## op-id/label
         label = QGraphicsSimpleTextItem(self._op_id)
         label.setScale(label.scale() / self._scale)
         center = self._component_item.boundingRect().center()
         center -= label.boundingRect().center() / self._scale
         label.setPos(self._component_item.pos() + center)
+        self._label_item = label
         
-        # execution time square
-        execution_time_path = QPainterPath(QPoint(0,0))
-        execution_time_path.addRect(0, 0, 20, self._height)
-
-        # execution time item
-        green_color = QColor(Qt.magenta)
-        green_color.setAlpha(200)               # 0-255
-        pen.setColor(green_color)
-        self._execution_time_item = QGraphicsPathItem(execution_time_path)
-        self._execution_time_item.setPen(pen)
+        ## execution time
+        if self._execution_time:
+            # execution time square
+            execution_time_path = QPainterPath(QPoint(0,0))
+            execution_time_path.addRect(0, 0, self._execution_time, self._height)
+            # execution time item
+            green_color = QColor(Qt.magenta)
+            green_color.setAlpha(200)               # 0-255
+            pen.setColor(green_color)
+            self._execution_time_item = QGraphicsPathItem(execution_time_path)
+            self._execution_time_item.setPen(pen)
         
-        # item group, consist of time_item and component_item
+        ## item group, consist of component_item, port_items and execution_time_item
         self.addToGroup(self._component_item)
-        self.addToGroup(label)
-        self.addToGroup(self._execution_time_item)
+        for port in port_items:
+            self.addToGroup(port)
+        self.addToGroup(self._label_item)
+        if self._execution_time:
+            self.addToGroup(self._execution_time_item)
 
     # move: https://evileg.com/en/post/86/
     # inherit QObject
diff --git a/b_asic/scheduler-gui/graphics_graph_event.py b/b_asic/scheduler-gui/graphics_graph_event.py
index f239a53e437eb54ab9a128dddd6d026d6b497856..b908d432eae63258df45b61d3adeb7eac3979412 100644
--- a/b_asic/scheduler-gui/graphics_graph_event.py
+++ b/b_asic/scheduler-gui/graphics_graph_event.py
@@ -152,18 +152,18 @@ class GraphicsGraphEvent(QGraphicsItem):
         # button = event.button()
         item = self.scene().mouseGrabberItem()
         dx = (item.mapToParent(event.pos()) - self._current_pos).x()
-        if dx > 5.05:
-            pos = item.x() + 10.0
+        if dx > 0.505:
+            pos = item.x() + 1.0
             if self.is_valid_pos(pos):
                 self.prepareGeometryChange()
                 item.setX(pos)
-                self._current_pos.setX(self._current_pos.x() + 10.0)
-        elif dx < -5.05:
-            pos = item.x() - 10.0
+                self._current_pos.setX(self._current_pos.x() + 1.0)
+        elif dx < -0.505:
+            pos = item.x() - 1.0
             if self.is_valid_pos(pos):
                 self.prepareGeometryChange()
                 item.setX(pos)
-                self._current_pos.setX(self._current_pos.x() - 10.0)
+                self._current_pos.setX(self._current_pos.x() - 1.0)
     
     def comp_mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
         """Changes the cursor to ClosedHandCursor when grabbing an object."""
diff --git a/b_asic/scheduler-gui/graphics_graph_item.py b/b_asic/scheduler-gui/graphics_graph_item.py
index 2096e4b3c59b15d07bd7499c11699d7fdcf68abc..a1b41c6166769936d0b6e03bcbc91bf2c12b29e9 100644
--- a/b_asic/scheduler-gui/graphics_graph_item.py
+++ b/b_asic/scheduler-gui/graphics_graph_item.py
@@ -52,53 +52,30 @@ class GraphicsGraphItem(QGraphicsItemGroup, GraphicsGraphEvent):
     
     def __init__(self, schedule: Schedule, parent: QGraphicsItem = None):
         super().__init__(parent)
-        
-        # self.setAcceptHoverEvents(True)
-        # print(f'GraphicsGraphItem.handlesChildEvents(): {self.handlesChildEvents()}')
-        # self.setHandlesChildEvents(True)   # PySide2 QGraphicsItemGroup default: true. PyQt5 not an option
-        
-        # # self.setFlag(QGraphicsItem.ItemIsMovable)
-        # # self.setFlag(QGraphicsItem.ItemIsSelectable)
-        # self.setAcceptHoverEvents(True)
-        # print(f'GraphicsGraphItem.handlesChildEvents(): {self.handlesChildEvents()}')
-        # self.setHandlesChildEvents(True)   # PySide2 QGraphicsItemGroup default: true. PyQt5 not an option
-        # # self.setAcceptedMouseButtons(Qt.NoButton)
-        
 
         self._schedule = deepcopy(schedule)
         self._axis = None
-        # self._components = QGraphicsItemGroup()
         self._components = []
-        # self._components.setHandlesChildEvents(False)
-        # self._components.setAcceptedMouseButtons(Qt.NoButton)
         self._components_height = 0.0
-        self._x_axis_indent = 2.0
+        self._x_axis_indent = 0.2
 
 
         # build components
-        spacing = 2.0
+        spacing = 0.2
         # print('Start times:')
-        for op_id, op_start_time in self._schedule._start_times.items():
-            op = self._schedule._sfg.find_by_id(op_id)
-            print(f'type: {type(op).__name__:<24}', end='\t')
-            print(op)
-            # slacks = self._schedule.slacks(op_id)
-            # print(f'{op_id:<5} {slacks}')
-            # op.latency_offsets -> [[int]]
-            # op.latency() -> int (max of all ports)
-            latency = op.latency_offsets
-            print(f'latency: {latency}')
+        for op_id, op_start_time in self.schedule.start_times.items():
+            op = self.schedule.sfg.find_by_id(op_id)
+            
             if not isinstance(op, (Input, Output)):
                 self._components_height += spacing
-                component = GraphicsComponentItem(op_id)
-                component.setPos(self._x_axis_indent + op_start_time*10, self._components_height)
+                component = GraphicsComponentItem(op_id, op.latency_offsets, op.execution_time)
+                component.setPos(self._x_axis_indent + op_start_time, self._components_height)
                 self._components.append(component)
                 self._components_height += component.height
         self._components_height += spacing
 
         # build axis
-        schedule_time: int = 0
-        schedule_time = self._schedule.schedule_time
+        schedule_time = self.schedule.schedule_time
         self._axis = GraphicsAxisItem(schedule_time, self._components_height, self._x_axis_indent)
 
         # add axis and components
@@ -119,8 +96,9 @@ class GraphicsGraphItem(QGraphicsItemGroup, GraphicsGraphEvent):
     def update_(self) -> None:
         # self.prepareGeometryChange()
         # self.removeFromGroup(self._axis)
-        self._axis.update(40 + 6, self._components_height, self._x_axis_indent)
+        # self._axis.update(40 + 6, self._components_height, self._x_axis_indent)
         # self.addToGroup(self._axis)
+        pass
         
     @property
     def schedule(self) -> Schedule:
diff --git a/b_asic/scheduler-gui/main_window.py b/b_asic/scheduler-gui/main_window.py
index 572a90041ec08b22bfb4abd77654d0054112d7a1..bf887e7ec769d7e8c02b3b3e0dc6cea3dfcb1063 100644
--- a/b_asic/scheduler-gui/main_window.py
+++ b/b_asic/scheduler-gui/main_window.py
@@ -126,7 +126,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         super().__init__()
         self._graph = None
         self._open_file_dialog_opened = False
-        self._scale = 7.5
+        self._scale = 75
         self._debug_rects = None
         
         QIcon.setThemeName('breeze')