Skip to content

Commit

Permalink
V2.0.1 (#211)
Browse files Browse the repository at this point in the history
* fix: progress bugfixes

* fix: truncate

* chore: add decorator on_elapsed

* chore: add array func

* feat: add color package
  • Loading branch information
jlsneto authored Sep 3, 2024
1 parent 4e42425 commit e4766bb
Show file tree
Hide file tree
Showing 15 changed files with 811 additions and 63 deletions.
2 changes: 1 addition & 1 deletion cereja/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from ._requests import request
from . import scraping

VERSION = "2.0.0.final.1"
VERSION = "2.0.1.final.0"

__version__ = get_version_pep440_compliant(VERSION)

Expand Down
73 changes: 73 additions & 0 deletions cereja/array/_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
"sub",
"prod",
"reshape",
"get_min_max",
"apply_proportional_mask",
]

from ..utils import is_iterable, is_sequence, is_numeric_sequence, chunk, dict_to_tuple
Expand Down Expand Up @@ -480,6 +482,77 @@ def dot(a, b):
return [[dotproduct(line, col) for col in get_cols(b)] for line in a]


def get_min_max(values: List[Any]) -> Tuple[Any, ...]:
if not values or len(values) == 0:
raise ValueError("values must have at least one element")

result = []
try:
shape = get_shape(values)
if len(shape) > 1:
values_ = flatten(values, depth=len(shape) - 2)
for i in range(shape[-1]):
result.append((min(values_, key=lambda val: val[i])[i], max(values_, key=lambda val: val[i])[i]))
return tuple(result)
return min(values), max(values)
except Exception as err:
raise ValueError(f"Error when trying to get min and max values. {err}")


def apply_proportional_mask(
positions: List[Tuple[int, int]],
mask_size: Tuple[int, int],
original_size: Optional[Tuple[int, int]] = None
) -> List[List[int]]:
"""
Applies a proportional mask to a list of positions and returns an array (list of lists) representing the mask,
where each index of the main list corresponds to a row.
Args:
positions (List[Tuple[int, int]]): List of tuples representing positions (x, y) on the original scale.
mask_size (Tuple[int, int]): Mask size (columns, rows), where columns is the number of columns and rows is
the number of rows.
original_size (Optional[Tuple[int, int]]): Original image size (width, height). If not provided, it will be
calculated based on positions.
Returns:
List[List[int]]: Matrix resulting from the proportional application of the mask, where each index represents a row.
"""

# If original_size is not given, calculate based on positions
min_x, max_x, min_y, max_y = 0, 0, 0, 0
if original_size is None:
(min_x, max_x), (min_y, max_y) = get_min_max(positions)
original_width = max_x - min_x
original_height = max_y - min_y
else:
original_width, original_height = original_size

mask_cols, mask_rows = mask_size

# Initialize the array with zeros
matrix = [[0 for _ in range(mask_cols)] for _ in range(mask_rows)]

# Calculate scale factors for columns and rows
scale_x = mask_cols / original_width
scale_y = mask_rows / original_height

# Fill the matrix based on the scaled positions
for x, y in positions:
# Adjust position to new coordinate system if necessary
if original_size is None:
x -= min_x
y -= min_y

scaled_x = int(x * scale_x)
scaled_y = int(y * scale_y)

if 0 <= scaled_x < mask_cols and 0 <= scaled_y < mask_rows:
matrix[scaled_y][scaled_x] = 1

return matrix


class Matrix(object):
"""
Matrix is ​​a tool similar to the numpy array
Expand Down
2 changes: 1 addition & 1 deletion cereja/concurrently/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@
SOFTWARE.
"""
from ._concurrence import TaskList, sync_to_async, async_to_sync
from .process import MultiProcess
from .process import MultiProcess, Processor
10 changes: 7 additions & 3 deletions cereja/concurrently/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,12 @@ def process(self, func, data, *args, **kwargs):
if elapsed_time < self.interval_seconds:
time.sleep(self.interval_seconds - elapsed_time)
if self.in_progress_count >= self._max_in_progress:
print(f"O Total de dados sendo processado {self.in_progress_count} é maior que o predefinido {self._max_in_progress}")
time.sleep(10)
print(
f"O Total de dados sendo processado {self.in_progress_count} é maior que o predefinido {self._max_in_progress}")
while self.in_progress_count >= self._max_in_progress * 0.9:
time.sleep(0.05)
if self.stopped:
break

self.stop_process()

Expand All @@ -345,4 +349,4 @@ def restart_process(self):
self._started_at = time.time()
self._failure_data = []
self._total_success = 0
self._create_process_result_service().start()
self._create_process_result_service().start()
38 changes: 27 additions & 11 deletions cereja/display/_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def restore_sys_module_state(self):


class _ConsoleBase(metaclass=ABC):
_instance = None
NON_BMP_MAP = dict.fromkeys(range(0x10000, sys.maxunicode + 1), 0xFFFD)
DONE_UNICODE = "\U00002705"
ERROR_UNICODE = "\U0000274C"
Expand Down Expand Up @@ -251,6 +252,11 @@ def __init__(self, color_text: str = "default"):
self.text_color = color_text
self._stdout = _Stdout(self)

def __new__(cls):
if cls._instance is None:
cls._instance = super(_ConsoleBase, cls).__new__(cls)
return cls._instance

@property
def non_bmp_supported(self):
from cereja import NON_BMP_SUPPORTED
Expand Down Expand Up @@ -718,7 +724,7 @@ def __init__(
self,
sequence=None,
name="Progress",
max_value: int = 100,
max_value: int = None,
states=("value", "bar", "percent", "time"),
custom_state_func=None,
custom_state_name=None,
Expand Down Expand Up @@ -757,18 +763,23 @@ def __init__(
def name(self):
return self._name

@property
def max_value(self):
return self._max_value or self._current_value + 1

def set_name(self, value: str):
if not isinstance(value, str):
raise TypeError("Please send string.")
self._name = value
self._console.set_prefix(f"{self._name}")

def _create_progress_service(self):
return threading.Thread(
name="awaiting", target=self._progress_service, daemon=True
)

def __repr__(self):
state = self._states_view(self._max_value)
state = self._states_view(self.max_value)
progress_example_view = f"{state}"
state_conf = f"{self.__class__.__name__}{self._parse_states()}"
return f"{state_conf}\n{self._console.parse(progress_example_view, title='Example States View')}"
Expand Down Expand Up @@ -821,7 +832,7 @@ def _states_view(self, for_value: Number) -> str:
self._n_times += 1
kwargs = {
"current_value": for_value,
"max_value": self._max_value,
"max_value": self.max_value,
"current_percent": self.percent_(for_value),
"time_it": self.time_it,
"n_times": self._n_times,
Expand Down Expand Up @@ -889,7 +900,7 @@ def states(self):
return self._parse_states()

def percent_(self, for_value: Number) -> Number:
return percent(for_value, self._max_value)
return percent(for_value, self.max_value)

def update_max_value(self, max_value: int):
"""
Expand All @@ -900,7 +911,7 @@ def update_max_value(self, max_value: int):
"""
if not isinstance(max_value, (int, float, complex)):
raise Exception(f"Current value {max_value} isn't valid.")
if max_value != self._max_value:
if max_value != self.max_value:
self._max_value = max_value

def _progress_service(self):
Expand All @@ -917,14 +928,14 @@ def _progress_service(self):
)
)
time.sleep(0.5)
if not self._awaiting_update or self._show:
if not self._awaiting_update or (self._show and self._max_value is not None):
self._show_progress(self._current_value)
last_value = self._current_value
time.sleep(0.01)

def _show_progress(self, for_value=None):
self._awaiting_update = False
build_progress = self._states_view(for_value)
build_progress = self._states_view(for_value or self._current_value)
self._console.replace_last_msg(
build_progress, end="\n" if self._iter_finaly else None
)
Expand Down Expand Up @@ -986,16 +997,18 @@ def prog(
cls,
sequence: Sequence[Any],
name: str = None,
max_value: int = None,
states=("value", "bar", "percent", "time"),
custom_state_func=None,
custom_state_name=None,
) -> "Progress":
return cls(
name=name,
max_value=max_value,
states=states,
custom_state_func=custom_state_func,
custom_state_name=custom_state_name,
)(sequence)
)(sequence, name, max_value)

def __len__(self):
return len(self._states)
Expand All @@ -1013,11 +1026,13 @@ def __getitem__(self, slice_):
raise KeyError(f"Not exists {key}")
return self._states[slice_]

def __call__(self, sequence: Sequence, name=None) -> "Progress":
def __call__(self, sequence: Sequence, name=None, max_value=None) -> "Progress":
if not is_iterable(sequence):
raise ValueError("Send a sequence.")
if has_length(sequence):
self.update_max_value(len(sequence))
elif max_value is not None:
self.update_max_value(max_value)
else:
self._is_generator = True
self.sequence = sequence
Expand All @@ -1030,6 +1045,7 @@ def __call__(self, sequence: Sequence, name=None) -> "Progress":
return self

def __next__(self):
original_name = self._name
if not self._with_context:
self.start()
try:
Expand All @@ -1041,13 +1057,13 @@ def __next__(self):
finally:
if self._is_generator:
self.update_max_value(self._current_value)
self._was_done = (self._current_value >= self._max_value) and not self._err
self._was_done = (self._current_value >= self.max_value) and not self._err
if not self._with_context:
self.stop()
self._iter_finaly = True
self._show_progress(self._current_value)

self._console.set_prefix(self.name)
self._console.set_prefix(original_name)
self.sequence = ()

def __iter__(self):
Expand Down
2 changes: 1 addition & 1 deletion cereja/geolinear/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .point import Point
from .utils import Rotation
from .utils import Rotation, find_best_locations
60 changes: 59 additions & 1 deletion cereja/geolinear/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import math

__all__ = ["Rotation"]
__all__ = ["Rotation", "find_best_locations"]

from typing import Union

Expand Down Expand Up @@ -74,3 +74,61 @@ def rotate(self, val, axis=None):

return reshape(list(map(lambda point: self.rotate_point(point, axis=axis), flatten(val, depth=len(shape) - 2))),
shape)


def find_best_locations(locations, min_distance=1):
"""
Finds the best locations that respect a minimum distance between points.
Args:
locations (list of tuple): A list of (x, y) tuples representing the locations.
min_distance (int, optional): The minimum distance in pixels between each point. Default is 1.
Returns:
list of tuple: A list of (x, y) tuples representing the best locations.
"""

min_distance_squared = min_distance ** 2
selected_locations = []

for current_location in locations:
is_valid = True
for existing_location in selected_locations:
distance_squared = (
(current_location[0] - existing_location[0]) ** 2 +
(current_location[1] - existing_location[1]) ** 2
)
if distance_squared < min_distance_squared:
is_valid = False
break
if is_valid:
selected_locations.append(current_location)

return selected_locations


def group_locations_into_rows(locations, max_distance=1):
"""
Groups locations into rows based on their y-coordinates.
Args:
locations (list of tuple): A list of (x, y) tuples representing the locations.
max_distance (int, optional): The maximum distance in pixels between each point. Default is 1.
Returns:
list of list of tuple: A list of lists of (x, y) tuples representing the grouped locations.
"""

rows = []

for location in locations:
is_added = False
for row in rows:
if all(abs(location[1] - row_location[1]) <= max_distance for row_location in row):
row.append(location)
is_added = True
break
if not is_added:
rows.append([location])

return rows
1 change: 1 addition & 0 deletions cereja/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
from . import colab
# Aliases here
from ._utils import get_batch_strides as stride_values
from . import colors
Loading

0 comments on commit e4766bb

Please sign in to comment.