feat: improve response plan display
This commit is contained in:
@@ -9,7 +9,7 @@ from .dataset import (
|
|||||||
to_human_readable_value,
|
to_human_readable_value,
|
||||||
from_human_readable_value,
|
from_human_readable_value,
|
||||||
)
|
)
|
||||||
from .query import Request, ResponsePriority, Response, ResponseItem
|
from .query import Request, ResponsePriority, Response, MAX_RESPONSE_CNT
|
||||||
from .resolver import Resolver, LutResolver, BfsResolver
|
from .resolver import Resolver, LutResolver, BfsResolver
|
||||||
|
|
||||||
_TStrEnum = TypeVar("_TStrEnum", bound=enum.StrEnum)
|
_TStrEnum = TypeVar("_TStrEnum", bound=enum.StrEnum)
|
||||||
@@ -76,6 +76,8 @@ class App:
|
|||||||
print('Type "help" for more info. Type "exit" to quit.')
|
print('Type "help" for more info. Type "exit" to quit.')
|
||||||
self.__op_main()
|
self.__op_main()
|
||||||
|
|
||||||
|
# region: Subcommand Processors
|
||||||
|
|
||||||
class MainCmd(enum.StrEnum):
|
class MainCmd(enum.StrEnum):
|
||||||
QUERY = "query"
|
QUERY = "query"
|
||||||
HELP = "help"
|
HELP = "help"
|
||||||
@@ -179,17 +181,8 @@ class App:
|
|||||||
index = current_page * (ITEMS_PER_PAGE - 1) + i
|
index = current_page * (ITEMS_PER_PAGE - 1) + i
|
||||||
if index >= cnt:
|
if index >= cnt:
|
||||||
continue
|
continue
|
||||||
# fetch item and print it
|
# and print it
|
||||||
item = response[index]
|
self.__illustrate_response(response, index)
|
||||||
print(
|
|
||||||
"Plan {0}\tValue: {1}\tDiff: {2} ({3:.2%})".format(
|
|
||||||
index + 1,
|
|
||||||
to_human_readable_value(item.value),
|
|
||||||
to_human_readable_value(item.difference),
|
|
||||||
item.relative_difference,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.__illustrate_circuit(item.circuit, response.device_kind)
|
|
||||||
|
|
||||||
# print page footer
|
# print page footer
|
||||||
print("")
|
print("")
|
||||||
@@ -204,6 +197,10 @@ class App:
|
|||||||
case App.PageViewerCmd.QUIT:
|
case App.PageViewerCmd.QUIT:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region: Command Utilities
|
||||||
|
|
||||||
def __accept_command(self, cmd_enum: type[_TStrEnum]) -> _TStrEnum:
|
def __accept_command(self, cmd_enum: type[_TStrEnum]) -> _TStrEnum:
|
||||||
"""
|
"""
|
||||||
Accept a command from the user.
|
Accept a command from the user.
|
||||||
@@ -223,8 +220,6 @@ class App:
|
|||||||
print("Unknown command, please try again.")
|
print("Unknown command, please try again.")
|
||||||
|
|
||||||
def __accept_count_value(self) -> int:
|
def __accept_count_value(self) -> int:
|
||||||
MAX_COUNT: int = 50
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
self.__show_prompt_arrow()
|
self.__show_prompt_arrow()
|
||||||
words = input()
|
words = input()
|
||||||
@@ -237,7 +232,7 @@ class App:
|
|||||||
print("Wrong value, please try again.")
|
print("Wrong value, please try again.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if value > MAX_COUNT or value <= 0:
|
if value > MAX_RESPONSE_CNT or value <= 0:
|
||||||
print("Wrong value, please try again.")
|
print("Wrong value, please try again.")
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
@@ -319,28 +314,35 @@ class App:
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __illustrate_circuit(self, circuit: Circuit, device_kind: DeviceKind) -> None:
|
# endregion
|
||||||
match circuit.device_scale:
|
|
||||||
case CircuitDeviceScale.ONE:
|
# region: Response Display
|
||||||
self.__illustrate_one_device_circuit(circuit, device_kind)
|
|
||||||
case CircuitDeviceScale.TWO:
|
|
||||||
self.__illustrate_two_device_circuit(circuit, device_kind)
|
|
||||||
case CircuitDeviceScale.THREE:
|
|
||||||
self.__illustrate_three_device_circuit(circuit, device_kind)
|
|
||||||
|
|
||||||
def __get_device_unit(self, device_kind: DeviceKind) -> str:
|
def __get_device_unit(self, device_kind: DeviceKind) -> str:
|
||||||
match device_kind:
|
match device_kind:
|
||||||
case DeviceKind.RESISTOR:
|
case DeviceKind.RESISTOR:
|
||||||
return '\u2126'
|
return "\u2126"
|
||||||
case DeviceKind.CAPACITOR:
|
case DeviceKind.CAPACITOR:
|
||||||
return 'F'
|
return "F"
|
||||||
case DeviceKind.INDUCTOR:
|
case DeviceKind.INDUCTOR:
|
||||||
return 'H'
|
return "H"
|
||||||
|
|
||||||
def __to_circult_graph_value(self, value: float, device_kind: DeviceKind) -> str:
|
def __to_circult_graph_value(self, value: float, device_kind: DeviceKind) -> str:
|
||||||
# Remove unit and append device unit
|
# Remove sign and append device unit
|
||||||
return to_human_readable_value(value)[1:] + self.__get_device_unit(device_kind)
|
return to_human_readable_value(value)[1:] + self.__get_device_unit(device_kind)
|
||||||
|
|
||||||
|
def __to_plan_head_value(self, value: float, device_kind: DeviceKind) -> str:
|
||||||
|
# Remove sign and append device unit
|
||||||
|
return to_human_readable_value(value)[1:] + self.__get_device_unit(device_kind)
|
||||||
|
|
||||||
|
def __to_plan_head_diff(self, value: float, device_kind: DeviceKind) -> str:
|
||||||
|
# Keep the sign and append device unit
|
||||||
|
return to_human_readable_value(value) + self.__get_device_unit(device_kind)
|
||||||
|
|
||||||
|
def __to_plan_head_diff_pct(self, value: float) -> str:
|
||||||
|
# Keep the sign and format it as percentage style without trailing device unit
|
||||||
|
return "{:.2%}".format(value)
|
||||||
|
|
||||||
# YYC MARK:
|
# YYC MARK:
|
||||||
# The function showing circuit graph should be maintained carefully.
|
# The function showing circuit graph should be maintained carefully.
|
||||||
# First, we want they are show in console properly,
|
# First, we want they are show in console properly,
|
||||||
@@ -362,11 +364,46 @@ class App:
|
|||||||
# This value should consider the length of f-string syntax, pre-defined chars and required chars.
|
# This value should consider the length of f-string syntax, pre-defined chars and required chars.
|
||||||
# To make sure a pretty showcase both in code and display.
|
# To make sure a pretty showcase both in code and display.
|
||||||
|
|
||||||
def __illustrate_one_device_circuit(self, circuit: Circuit, device_kind: DeviceKind) -> None:
|
def __illustrate_response(self, response: Response, index: int) -> None:
|
||||||
|
"""
|
||||||
|
Illustrate response item with given response and item.
|
||||||
|
|
||||||
|
:param response: The response to illustrate.
|
||||||
|
:param index: The zero-based index of the item to illustrate.
|
||||||
|
"""
|
||||||
|
# fetch item and device kind from response
|
||||||
|
item = response[index]
|
||||||
|
device_kind = response.device_kind
|
||||||
|
# print header
|
||||||
|
print(
|
||||||
|
"Plan {0:<4} Value: {1:<16} Diff: {2} ({3})".format(
|
||||||
|
index + 1,
|
||||||
|
self.__to_plan_head_value(item.value, device_kind),
|
||||||
|
self.__to_plan_head_diff(item.difference, device_kind),
|
||||||
|
self.__to_plan_head_diff_pct(item.relative_difference),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# print circuit graph
|
||||||
|
self.__illustrate_circuit(item.circuit, device_kind)
|
||||||
|
|
||||||
|
def __illustrate_circuit(self, circuit: Circuit, device_kind: DeviceKind) -> None:
|
||||||
|
match circuit.device_scale:
|
||||||
|
case CircuitDeviceScale.ONE:
|
||||||
|
self.__illustrate_one_device_circuit(circuit, device_kind)
|
||||||
|
case CircuitDeviceScale.TWO:
|
||||||
|
self.__illustrate_two_device_circuit(circuit, device_kind)
|
||||||
|
case CircuitDeviceScale.THREE:
|
||||||
|
self.__illustrate_three_device_circuit(circuit, device_kind)
|
||||||
|
|
||||||
|
def __illustrate_one_device_circuit(
|
||||||
|
self, circuit: Circuit, device_kind: DeviceKind
|
||||||
|
) -> None:
|
||||||
dev1 = self.__to_circult_graph_value(circuit.first_device_value, device_kind)
|
dev1 = self.__to_circult_graph_value(circuit.first_device_value, device_kind)
|
||||||
print(f"──[{dev1:^16}]──")
|
print(f"──[{dev1:^16}]──")
|
||||||
|
|
||||||
def __illustrate_two_device_circuit(self, circuit: Circuit, device_kind: DeviceKind) -> None:
|
def __illustrate_two_device_circuit(
|
||||||
|
self, circuit: Circuit, device_kind: DeviceKind
|
||||||
|
) -> None:
|
||||||
dev1 = self.__to_circult_graph_value(circuit.first_device_value, device_kind)
|
dev1 = self.__to_circult_graph_value(circuit.first_device_value, device_kind)
|
||||||
j2 = circuit.second_device_joint
|
j2 = circuit.second_device_joint
|
||||||
dev2 = self.__to_circult_graph_value(circuit.second_device_value, device_kind)
|
dev2 = self.__to_circult_graph_value(circuit.second_device_value, device_kind)
|
||||||
@@ -374,12 +411,14 @@ class App:
|
|||||||
case JointKind.SERIES:
|
case JointKind.SERIES:
|
||||||
print(f"──[{dev1:^16}]──[{dev2:^16}]──")
|
print(f"──[{dev1:^16}]──[{dev2:^16}]──")
|
||||||
case JointKind.PARALLEL:
|
case JointKind.PARALLEL:
|
||||||
SEP0: str = ' ' * (6 + (16 - 10))
|
SEP0: str = " " * (6 + (16 - 10))
|
||||||
print(f" ┌──[{dev1:^16}]──┐ ")
|
print(f" ┌──[{dev1:^16}]──┐ ")
|
||||||
print(f"──┤ {SEP0} ├──")
|
print(f"──┤ {SEP0} ├──")
|
||||||
print(f" └──[{dev2:^16}]──┘ ")
|
print(f" └──[{dev2:^16}]──┘ ")
|
||||||
|
|
||||||
def __illustrate_three_device_circuit(self, circuit: Circuit, device_kind: DeviceKind) -> None:
|
def __illustrate_three_device_circuit(
|
||||||
|
self, circuit: Circuit, device_kind: DeviceKind
|
||||||
|
) -> None:
|
||||||
dev1 = self.__to_circult_graph_value(circuit.first_device_value, device_kind)
|
dev1 = self.__to_circult_graph_value(circuit.first_device_value, device_kind)
|
||||||
j2 = circuit.second_device_joint
|
j2 = circuit.second_device_joint
|
||||||
dev2 = self.__to_circult_graph_value(circuit.second_device_value, device_kind)
|
dev2 = self.__to_circult_graph_value(circuit.second_device_value, device_kind)
|
||||||
@@ -393,8 +432,8 @@ class App:
|
|||||||
print(f"──[{dev1:^16}]──[{dev2:^16}]──[{dev3:^16}]──")
|
print(f"──[{dev1:^16}]──[{dev2:^16}]──[{dev3:^16}]──")
|
||||||
case JointKind.PARALLEL:
|
case JointKind.PARALLEL:
|
||||||
# First series then parallel
|
# First series then parallel
|
||||||
SEP0: str = '─' * (6 + ((16 - 10) // 2))
|
SEP0: str = "─" * (6 + ((16 - 10) // 2))
|
||||||
SEP1: str = ' ' * (6 + 2 * (16 - 10))
|
SEP1: str = " " * (6 + 2 * (16 - 10))
|
||||||
print(f" ┌──[{dev1:^16}]──[{dev2:^16}]──┐ ")
|
print(f" ┌──[{dev1:^16}]──[{dev2:^16}]──┐ ")
|
||||||
print(f"──┤ {SEP1} ├──")
|
print(f"──┤ {SEP1} ├──")
|
||||||
print(f" └───{SEP0}[{dev3:^16}]{SEP0}───┘ ")
|
print(f" └───{SEP0}[{dev3:^16}]{SEP0}───┘ ")
|
||||||
@@ -402,7 +441,7 @@ class App:
|
|||||||
match j3:
|
match j3:
|
||||||
case JointKind.SERIES:
|
case JointKind.SERIES:
|
||||||
# First parallel then series
|
# First parallel then series
|
||||||
SEP0: str = ' ' * (6 + (16 - 10))
|
SEP0: str = " " * (6 + (16 - 10))
|
||||||
print(f" {SEP0} ┌──[{dev1:^16}]──┐ ")
|
print(f" {SEP0} ┌──[{dev1:^16}]──┐ ")
|
||||||
print(f"──[{dev1:^16}]──┤ {SEP0} ├──")
|
print(f"──[{dev1:^16}]──┤ {SEP0} ├──")
|
||||||
print(f" {SEP0} └──[{dev2:^16}]──┘ ")
|
print(f" {SEP0} └──[{dev2:^16}]──┘ ")
|
||||||
@@ -412,6 +451,8 @@ class App:
|
|||||||
print(f"──┼──[{dev2:^16}]──┼──")
|
print(f"──┼──[{dev2:^16}]──┼──")
|
||||||
print(f" └──[{dev3:^16}]──┘ ")
|
print(f" └──[{dev3:^16}]──┘ ")
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
|
|||||||
@@ -217,6 +217,9 @@ def to_human_readable_value(v: float) -> str:
|
|||||||
case UnitScale.MILLI:
|
case UnitScale.MILLI:
|
||||||
return "{:+.4f} m".format(v / 1e-3)
|
return "{:+.4f} m".format(v / 1e-3)
|
||||||
case UnitScale.NONE:
|
case UnitScale.NONE:
|
||||||
|
# YYC MARK:
|
||||||
|
# The space of this format string is by design
|
||||||
|
# for keeping the same style with other format strings.
|
||||||
return "{:+.4f} ".format(v)
|
return "{:+.4f} ".format(v)
|
||||||
case UnitScale.KILO:
|
case UnitScale.KILO:
|
||||||
return "{:+.4f} k".format(v / 1e3)
|
return "{:+.4f} k".format(v / 1e3)
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ class ResponsePriority(enum.Enum):
|
|||||||
"""More accuracy is the first priority."""
|
"""More accuracy is the first priority."""
|
||||||
|
|
||||||
|
|
||||||
|
MAX_RESPONSE_CNT: int = 50
|
||||||
|
"""The maximum count for the response item count passed in request."""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Request:
|
class Request:
|
||||||
"""
|
"""
|
||||||
@@ -33,6 +37,21 @@ class Request:
|
|||||||
count_limit: int
|
count_limit: int
|
||||||
"""The limited count of results."""
|
"""The limited count of results."""
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
target_value = self.target_value
|
||||||
|
if target_value <= 0:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid value {target_value} for target value in request."
|
||||||
|
)
|
||||||
|
tolerance = self.tolerance
|
||||||
|
if tolerance < 0:
|
||||||
|
raise ValueError(f"Invalid value {tolerance} for tolerance in request.")
|
||||||
|
count_limit = self.count_limit
|
||||||
|
if count_limit <= 0 or count_limit > MAX_RESPONSE_CNT:
|
||||||
|
raise ValueError(
|
||||||
|
f"Too large or too less value {count_limit} for response count limit in request."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ResponseItem:
|
class ResponseItem:
|
||||||
"""
|
"""
|
||||||
@@ -94,7 +113,9 @@ class ResponseItem:
|
|||||||
|
|
||||||
:return: The unsigned difference.
|
:return: The unsigned difference.
|
||||||
"""
|
"""
|
||||||
return self.__cv_trait.unsigned_difference(self.__circuit, difference=self.difference)
|
return self.__cv_trait.unsigned_difference(
|
||||||
|
self.__circuit, difference=self.difference
|
||||||
|
)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def relative_difference(self) -> float:
|
def relative_difference(self) -> float:
|
||||||
@@ -106,7 +127,9 @@ class ResponseItem:
|
|||||||
|
|
||||||
:return: The signed relative difference.
|
:return: The signed relative difference.
|
||||||
"""
|
"""
|
||||||
return self.__cv_trait.relative_difference(self.__circuit, difference=self.difference)
|
return self.__cv_trait.relative_difference(
|
||||||
|
self.__circuit, difference=self.difference
|
||||||
|
)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def unsigned_relative_difference(self) -> float:
|
def unsigned_relative_difference(self) -> float:
|
||||||
@@ -137,9 +160,7 @@ class Response:
|
|||||||
def __init__(self, request: Request, candidates: Iterable[Circuit]) -> None:
|
def __init__(self, request: Request, candidates: Iterable[Circuit]) -> None:
|
||||||
cv_trait = CircuitValueTrait(request.device_kind, request.target_value)
|
cv_trait = CircuitValueTrait(request.device_kind, request.target_value)
|
||||||
self.__device_kind = request.device_kind
|
self.__device_kind = request.device_kind
|
||||||
self.__sorted_items = list(
|
self.__sorted_items = list(ResponseItem(item, cv_trait) for item in candidates)
|
||||||
ResponseItem(item, cv_trait) for item in candidates
|
|
||||||
)
|
|
||||||
|
|
||||||
# Sort by different strategy
|
# Sort by different strategy
|
||||||
match request.response_priority:
|
match request.response_priority:
|
||||||
|
|||||||
Reference in New Issue
Block a user