Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

common/lib/geometry: Test docs #204

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions opencsp/common/lib/file/CsvColumns.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,26 @@


class CsvColumns:
"""
A class to help parse CSV files with a tentative structure by finding column name matches.
This class allows for the definition of expected column names and their aliases,
and provides methods to parse the header and data rows of a CSV file.
"""

# "ChatGPT 4o" assisted with generating this docstring.
def __init__(self, columns: dict[str, list[str | re.Pattern]]):
"""Helps to parse csv files that have a tentative structure to them by finding column name matches.
"""
Initializes the CsvColumns instance with the provided column definitions.
Helps to parse csv files that have a tentative structure to them by finding column name matches.
Example::
Parameters
----------
columns : dict[str, list[str | re.Pattern]]
The anticipated column names and their corresponding aliases or regex patterns.
Example
-------
cols = cc.CsvColumns({
'latitude': ['lat'],
'datetime': ['UTC', 'localtime', re.compile(r"^dt")]
Expand All @@ -20,21 +35,50 @@ def __init__(self, columns: dict[str, list[str | re.Pattern]]):
cols.parse_header(rows[0])
lat = float(rows[1][cols['latitude']])
dt = datetime.fromisoformat(rows[1][cols['datetime']])
Args:
columns (dict[str,list[str | re.Pattern]]): The anticipated column names to patterns to match those column names.
"""
# "ChatGPT 4o" assisted with generating this docstring.
self.columns = {k: _ColumnHeader(k, columns[k], -1) for k in columns}

@classmethod
def SimpleColumns(cls, header_row: list[str]):
"""Simple constructor that creates columns and column names from the header."""
"""
Creates a CsvColumns instance from a simple header row.
This method initializes the columns using the header row as both the names and aliases.
Parameters
----------
header_row : list[str]
A list of column names from the CSV header.
Returns
-------
CsvColumns
An instance of CsvColumns initialized with the provided header row.
"""
# "ChatGPT 4o" assisted with generating this docstring.
columns = {v: [v] for v in header_row}
ret = cls(columns)
ret.parse_header(header_row)
return ret

def parse_data_row(self, data_row: list[str], row_idx=-1):
"""
Parses a data row and extracts values based on the matched column indices.
Parameters
----------
data_row : list[str]
A list of values from a single row of the CSV file.
row_idx : int, optional
The index of the row being parsed, used for logging. Defaults to -1.
Returns
-------
dict[str, str]
A dictionary mapping column names to their corresponding values from the data row.
"""
# "ChatGPT 4o" assisted with generating this docstring.
ret: dict[str, str] = {}
last_matched_idx = -1

Expand All @@ -61,6 +105,24 @@ def parse_header(
ok_if_not_found: list[str] = None,
alternatives: dict[str, list[str]] = None,
):
"""
Parses the header row to find matches for the defined columns.
This method updates the column indices based on the header row and checks for
any missing columns, logging warnings or raising errors as specified.
Parameters
----------
header_row : list[str]
A list of column names from the CSV header.
error_on_not_found : bool | list[str], optional
If True, raises an error for any missing columns. If a list, raises an error for columns in that list. Defaults to True.
ok_if_not_found : list[str], optional
A list of column names that are acceptable to be missing. Defaults to None.
alternatives : dict[str, list[str]], optional
A dictionary mapping column names to lists of alternative names. Defaults to None.
"""
# "ChatGPT 4o" assisted with generating this docstring.
# add reverse values for the alternatives, if any
if alternatives != None:
ks = list(alternatives.keys())
Expand Down
66 changes: 58 additions & 8 deletions opencsp/common/lib/file/SimpleCsv.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,42 @@


class SimpleCsv:
"""
A class for simple parsing of CSV files.
This class allows for reading a CSV file and provides methods to access
the header, columns, and rows of the file in a structured manner.
"""

# "ChatGPT 4o" assisted with generating this docstring.
def __init__(self, description: str, file_path: str, file_name_ext: str):
"""Allows for simple CSV file parsing.
"""
Initializes the SimpleCsv instance and parses the CSV file.
Parameters
----------
description : str
A description of the file to be processed, or None to suppress output to stdout.
file_path : str
The path to the CSV file to be processed.
file_name_ext : str
The name and extension of the CSV file to be processed.
Example::
Raises
------
FileNotFoundError
If the specified CSV file does not exist.
ValueError
If the CSV file is empty or improperly formatted.
Example
-------
parser = scsv.SimpleCsv("example file", file_path, file_name_ext)
for row_dict in parser:
print(row_dict)
Parameters:
-----------
- description (str): A description of the file to be processed, or None to not print to stdout.
- file_path (str): Path to the file to be processed.
- file_name_ext (str): Name and extension of the file to be processed.
"""
# "ChatGPT 4o" assisted with generating this docstring.
self.description = description
self.file_path = file_path
self.file_name_ext = file_name_ext
Expand All @@ -32,12 +53,41 @@ def __init__(self, description: str, file_path: str, file_name_ext: str):
self.rows.append(self.cols.parse_data_row(row))

def get_header(self):
"""
Returns the header of the CSV file as a comma-separated string.
Returns
-------
str
A string representation of the header row of the CSV file.
"""
# "ChatGPT 4o" assisted with generating this docstring.
return ",".join(self.get_columns())

def get_columns(self):
"""
Returns a list of column names from the CSV file.
Returns
-------
list[str]
A list of column names extracted from the CSV header.
"""
# "ChatGPT 4o" assisted with generating this docstring.
return [col.name for col in self.cols.columns.values]

def get_rows(self):
"""
Returns the rows of the CSV file as a list of dictionaries.
Each dictionary corresponds to a row in the CSV file, with column names as keys.
Returns
-------
list[dict[str, str]]
A list of dictionaries representing the rows of the CSV file.
"""
# "ChatGPT 4o" assisted with generating this docstring.
return self.rows

def __iter__(self):
Expand Down
4 changes: 4 additions & 0 deletions opencsp/common/lib/geometry/EdgeXY.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@


class EdgeXY:
"""
Representation of a 2D edge.
"""

def __init__(self, vertices: Vxy, curve_data: dict = {'type': 'line'}, closed: bool = False):
"""
Representation of a 2D edge.
Expand Down
94 changes: 88 additions & 6 deletions opencsp/common/lib/geometry/FunctionXYDiscrete.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,24 @@


class FunctionXYDiscrete(FunctionXYAbstract):
"""
A class representing a discrete function defined by scattered (x, y) points and their corresponding values.

This class allows for the evaluation of function values at specified (x, y) coordinates
and provides methods for checking if points are within the function's domain.
"""

# "ChatGPT 4o-mini" assisted with generating this docstring.
def __init__(self, values: dict[tuple[float, float], float]) -> None:
"""
Initializes a FunctionXYDiscrete object with the specified values.

Parameters
----------
values : dict[tuple[float, float], float]
A dictionary mapping (x, y) coordinate pairs to their corresponding function values.
"""
# "ChatGPT 4o-mini" assisted with generating this docstring.
super().__init__()
self.values = values
x_domain, y_domain = tuple(zip(*values.keys()))
Expand All @@ -25,6 +42,27 @@ def __init__(self, values: dict[tuple[float, float], float]) -> None:
# ...

def value_at(self, x: float | Iterable[float], y: float | Iterable[float]) -> float | np.ndarray[float]:
"""
Retrieves the function value at the specified (x, y) coordinates.

Parameters
----------
x : float or Iterable[float]
The x-coordinate(s) at which to evaluate the function.
y : float or Iterable[float]
The y-coordinate(s) at which to evaluate the function.

Returns
-------
float or np.ndarray
The function value(s) at the specified coordinates.

Raises
------
ValueError
If the (x, y) pair is not within the domain of the function or if the lengths of x and y do not match.
"""
# "ChatGPT 4o-mini" assisted with generating this docstring.
if isinstance(x, Iterable) and isinstance(y, Iterable):
if len(x) != len(y):
raise ValueError(
Expand All @@ -38,10 +76,40 @@ def value_at(self, x: float | Iterable[float], y: float | Iterable[float]) -> fl
raise ValueError("(x,y) pair not within domain")

def in_domain(self, x: float, y: float) -> bool:
"""Takes in a pair of elements in the form (x:float, y:float) and returns true if the pair is in the domain of self."""
"""
Checks if the specified (x, y) coordinates are within the domain of the function.

Parameters
----------
x : float
The x-coordinate to check.
y : float
The y-coordinate to check.

Returns
-------
bool
True if the (x, y) pair is within the domain, False otherwise.
"""
# "ChatGPT 4o-mini" assisted with generating this docstring.
return (x, y) in list(self.values.keys())

def draw(self, view: View3d, functionXY_style):
"""
Draws the function in a 3D view.

Parameters
----------
view : View3d
The 3D view in which to draw the function.
functionXY_style : RenderControlMirror
The style settings for rendering the function.

Returns
-------
None
"""
# "ChatGPT 4o-mini" assisted with generating this docstring.
if view.view_spec['type'] == 'image':
# X, Y = np.meshgrid(self.x_domain, self.y_domain)
arr = np.zeros((len(self.y_domain), len(self.x_domain)))
Expand All @@ -56,14 +124,28 @@ def draw(self, view: View3d, functionXY_style):
@classmethod
def from_array(cls, x_domain: np.ndarray, y_domain: np.ndarray, values: np.ndarray):
"""
Create an instance of FunctionXYDiscrete using a 2d array
Creates an instance of FunctionXYDiscrete using a 2D array.

Parameters
-----------
x_domain: array, the values of x that will be used to access values of the array
y_domain: array, the values of y that will be used to access values of the array
values: 2d array, the values that will be returned when x and y are used
----------
x_domain : np.ndarray
The values of x that will be used to access values of the array.
y_domain : np.ndarray
The values of y that will be used to access values of the array.
values : np.ndarray
A 2D array containing the values that will be returned when x and y are used.

Returns
-------
FunctionXYDiscrete
An instance of FunctionXYDiscrete initialized with the provided domains and values.

Raises
------
ValueError
If the size of the domain does not match the size of the value array.
"""
# "ChatGPT 4o-mini" assisted with generating this docstring.
if len(values) != len(y_domain) or len(values[0]) != len(x_domain):
raise ValueError("Size of the domain does not match size of the value array.")
else:
Expand Down
Loading
Loading