ccfx 1.2.0
This package simplifies regular common actions for quick prototyping in a user friendly way
Requires Python: >=3.10

# ccfx

[![PyPI version](https://badge.fury.io/py/ccfx.svg)](https://badge.fury.io/py/ccfx)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![GitHub stars](https://img.shields.io/github/stars/celray/ccfx.svg)](https://github.com/celray/ccfx/stargazers)

`ccfx` is a comprehensive Python package designed to streamline file and data management, geospatial analysis, NetCDF file processing, database interactions, document generation, and multimedia handling for rapid prototyping and development workflows.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Dependencies](#dependencies)
- [Usage Examples](#usage-examples)
- [API Reference](#api-reference-selected-functions)
  - [File Management](#file-management-ccfxpy)
  - [Geospatial](#geospatial-ccfxpy)
  - [NetCDF](#netcdf-ccfxpy)
  - [Database](#database-mssqlconnectionpy-sqliteconnectionpy)
  - [Document/Spreadsheet](#documentspreadsheet-wordpy-excelpy)
  - [Multimedia & Web](#multimedia--web-ccfxpy)
  - [Data Analysis & Utilities](#data-analysis--utilities-ccfxpy)
- [System Requirements](#system-requirements)
- [Contributing](#contributing)
- [Changelog](#changelog)
- [License](#license)

## Features

1.  **File Management**:
    *   List, delete, move, copy, and count files/directories.
    *   Monitor file count over time.
    *   Save, load, and manage Python variables via pickle serialization.
    *   Compress directories to `.7z` archives.
    *   Read/write text files with encoding support.
    *   Download files from URLs with resume and multi-connection support.

2.  **Geospatial Data Processing**:
    *   Read, write, clip (by extent/feature), resample, reproject, merge, and rasterize raster data (GeoTIFF, NetCDF).
    *   Read, write, and clip vector data (Shapefile, GeoPackage).
    *   Create grids of polygons based on shapefile boundaries.
    *   Convert coordinates between Coordinate Reference Systems (CRS).
    *   Extract raster values at specific coordinates.
    *   Convert point lists to GeoDataFrames.
    *   Get vector layer bounds.

3.  **NetCDF File Handling**:
    *   List variables and dimensions.
    *   Export NetCDF variables to GeoTIFF format (single or multiple bands).
    *   Calculate sum and average maps from NetCDF data across multiple files.
    *   Rename variables using CDO (if available).

4.  **Database Connectivity**:
    *   **MS SQL Server**: Connect, list databases/tables, read tables (including spatial data into GeoDataFrames), write DataFrames/GeoDataFrames to tables, drop tables.
    *   **SQLite**: Connect, create/rename/drop tables, read tables (as dict, specific columns), insert data (rows, dicts, partial dicts), update values, dump tables to CSV.

5.  **Document & Spreadsheet Handling**:
    *   **Excel**: Create `.xlsx` files, add sheets, write data (including dates), set column widths, add scatter plot charts.
    *   **Word**: Create `.docx` files, add headings, paragraphs (with alignment), list items, formatted text (bold/italic), images, page breaks, set margins.

6.  **Multimedia & Web**:
    *   Read and write MP3 metadata (ID3 tags), including album art.
    *   Download videos/audio from YouTube using `yt-dlp`.

7.  **Data Analysis & Utilities**:
    *   Calculate timeseries statistics (NSE, KGE, PBIAS, LNSE, R2, RMSE, MAE, MSE, MAPE, alpha, beta) with resampling options.
    *   Display dynamic progress bars.
    *   Check system platform information.
    *   Enable or disable warnings programmatically.
    *   Set the working directory.

## Installation

Install `ccfx` via pip:
```bash
pip install ccfx
```

> **Note**: GDAL is a core dependency and may require additional system-level installation steps. See [System Requirements](#system-requirements) for details.

## Quick Start

Here's a simple example to get you started with `ccfx`:

```python
import ccfx

# File management
files = ccfx.listFiles("/path/to/directory", ext=".txt")
print(f"Found {len(files)} text files")

# Create and save data to Excel
excel_doc = ccfx.excel("output.xlsx")
excel_doc.create()
excel_doc.addSheet("MyData")
excel_doc.write("A1", "Hello, ccfx!")
excel_doc.save()

# Work with geospatial data
bounds = (-180, -90, 180, 90)  # Global bounds
ccfx.clipRasterByExtent("input.tif", "clipped.tif", bounds)

# Download and process data
ccfx.downloadFile("https://example.com/data.zip", "./data.zip")
ccfx.compressTo7z("./my_folder", "archive.7z")
```

## Dependencies

`ccfx` relies on the following libraries (automatically installed with pip):

### Core Dependencies
*   **gdal**: For geospatial raster and vector data manipulation.
*   **numpy**: For array processing and numerical operations.
*   **pandas**: For data manipulation and analysis.
*   **geopandas**: Extends pandas to handle geospatial vector data.
*   **shapely**: Provides geometric objects and operations.
*   **netCDF4**: For working with NetCDF files.
*   **rasterio**: Advanced raster I/O and processing.

### Document & Database
*   **xlsxwriter**: For creating and writing Excel `.xlsx` files.
*   **python-docx**: Enables creation and manipulation of Word `.docx` documents.
*   **pyodbc**: Enables connectivity to databases through ODBC (e.g., MS SQL Server).
*   **sqlalchemy**: Provides SQL toolkit and ORM features for database access.

### Utilities & Multimedia
*   **py7zr**: For creating `.7z` archives.
*   **mutagen**: For reading and writing MP3 metadata (ID3 tags).
*   **requests**: For downloading files via HTTP.
*   **tqdm**: For displaying progress bars.
*   **yt-dlp**: For downloading YouTube content.
*   **pillow**: For image processing.
*   **scipy**: For scientific computing.
*   **matplotlib**: For plotting and visualization.

## System Requirements

### Python Version
- **Python 3.10+** is required

### GDAL Installation
GDAL can be challenging to install depending on your operating system:

#### Windows
```bash
# Using conda (recommended)
conda install -c conda-forge gdal

# Or using pip with pre-compiled binaries
pip install GDAL

# Alternative: If struggling with GDAL installation on Windows
pip install gdal-installer
install-gdal
```

#### macOS
```bash
# Using Homebrew
brew install gdal
pip install gdal

# Using conda
conda install -c conda-forge gdal
```

#### Linux (Ubuntu/Debian)
```bash
# Install system dependencies
sudo apt-get update
sudo apt-get install gdal-bin libgdal-dev

# Install Python bindings
pip install gdal
```

#### Docker
For a hassle-free setup, consider using the official GDAL Docker images:
```bash
docker pull ghcr.io/osgeo/gdal:ubuntu-small-latest
```

## Usage Examples

### File Management
```python
import ccfx

# List all Python files in a directory
python_files = ccfx.listFiles("/path/to/project", ext=".py")

# Create a backup directory and copy files
ccfx.createPath("/backup/location")
ccfx.copyDirectory("/source/dir", "/backup/location")

# Compress a directory
ccfx.compressTo7z("/data/folder", "backup.7z")

# Download a file with resume capability
ccfx.downloadFile(
    "https://example.com/largefile.zip", 
    "downloaded_file.zip", 
    exists_action='resume'
)
```

### Geospatial Data Processing
```python
import ccfx

# Clip a raster to a specific bounding box
bounds = (-74.0, 40.7, -73.9, 40.8)  # NYC area
ccfx.clipRasterByExtent("satellite_image.tif", "nyc_clip.tif", bounds)

# Resample a raster to different resolution
ccfx.resampleRaster(
    "high_res.tif", 
    "low_res.tif", 
    resolution=1000,  # 1km resolution
    resamplingMethod='bilinear'
)

# Convert coordinates between projections
lat, lon = 40.7128, -74.0060  # NYC coordinates
x, y = ccfx.convertCoordinates(lon, lat, "EPSG:4326", "EPSG:3857")

# Extract raster value at specific point
value = ccfx.extractRasterValue("elevation.tif", 40.7128, -74.0060)
print(f"Elevation at NYC: {value}")
```

### Database Operations
```python
import ccfx

# SQLite operations
db = ccfx.sqliteConnection("my_data.db", connect=True)
db.createTable("users", ["id INTEGER PRIMARY KEY", "name TEXT", "email TEXT"])
db.insertDict("users", {"name": "John Doe", "email": "john@example.com"})
users = db.readTableAsDict("users")
db.closeConnection()

# MS SQL Server operations
mssql = ccfx.mssql_connection("server", "username", "password", "driver")
mssql.connect()
databases = mssql.listDatabases()
df = mssql.readTable("MyDatabase", "MyTable")
mssql.close()
```

### Document Generation
```python
import ccfx

# Create Excel spreadsheet
excel = ccfx.excel("report.xlsx")
excel.create()
excel.addSheet("Sales Data")
excel.write("A1", "Product")
excel.write("B1", "Revenue")
excel.writeColumn("A", ["Product A", "Product B", "Product C"], start_row=2)
excel.writeColumn("B", [1000, 1500, 800], start_row=2)
excel.save()

# Create Word document
doc = ccfx.word_document("report.docx")
doc.addHeading("Monthly Report", level=1)
doc.addParagraph("This report summarizes our monthly performance.")
doc.addListItem("Revenue increased by 15%")
doc.addListItem("Customer satisfaction improved")
doc.save()
```

### NetCDF Processing
```python
import ccfx

# List variables in NetCDF file
variables = ccfx.netcdfVariablesList("climate_data.nc")
print("Available variables:", variables)

# Export NetCDF variable to GeoTIFF
ccfx.netcdfExportTif(
    "temperature_data.nc", 
    "temperature", 
    "temp_map.tif",
    band=1
)

# Calculate average from multiple NetCDF files
nc_files = ["data_2020.nc", "data_2021.nc", "data_2022.nc"]
avg_map = ccfx.netcdfAverageMap(nc_files, "precipitation")
```

### Data Analysis
```python
import ccfx
import pandas as pd

# Calculate timeseries statistics
observed_data = pd.read_csv("observed.csv")
simulated_data = pd.read_csv("simulated.csv")

# Combine data
data = pd.merge(observed_data, simulated_data, on='date')

# Calculate Nash-Sutcliffe Efficiency
stats = ccfx.calculateTimeseriesStats(data, observed='obs', simulated='sim')
print(f"NSE: {stats['NSE']:.3f}")
print(f"KGE: {stats['KGE']:.3f}")
print(f"R²: {stats['R2']:.3f}")
```

## API Reference (Complete Function List)

### File & Directory Management (`ccfx.py`)

**Basic File Operations:**
*   **`listFiles(path: str, ext: Optional[str] = None) -> list`**: Lists files in a directory, optionally filtering by extension.
*   **`listAllFiles(folder: str, extension: str = "*") -> list`**: Recursively lists all files in a folder and its subfolders.
*   **`listFolders(path: str) -> list`**: Lists all folders in a directory.
*   **`listDirectories(path: str) -> list`**: Alias for listFolders.
*   **`deleteFile(filePath: str, v: bool = False) -> bool`**: Deletes a specified file.
*   **`deletePath(path: str, v: bool = False) -> bool`**: Deletes a directory and its contents.
*   **`createPath(pathName: str, v: bool = False) -> str`**: Creates a directory path if it doesn't exist.
*   **`getExtension(filePath: str) -> str`**: Gets the extension of a file.
*   **`getFileBaseName(filePath: str, extension: bool = True) -> str`**: Gets the base name of a file.

**File Copying & Moving:**
*   **`copyFile(source: str, destination: str, v: bool = True) -> None`**: Copies a single file.
*   **`copyDirectory(source: str, destination: str, recursive: bool = True, v: bool = True, filter: list = []) -> None`**: Copies a directory's contents.
*   **`copyFolder(source: str, destination: str, v: bool = True) -> None`**: Alias for copyDirectory.
*   **`moveDirectory(srcDir: str, destDir: str, v: bool = False) -> bool`**: Moves all files from source to destination directory.
*   **`moveDirectoryFiles(srcDir: str, destDir: str, v: bool = False) -> bool`**: Moves files and subdirectories from source to destination.

**File I/O Operations:**
*   **`readFrom(filename: str, decode_codec: Optional[str] = None, v: bool = False) -> Any`**: Reads ASCII files.
*   **`readFile(filename: str, decode_codec: Optional[str] = None, v: bool = False) -> Any`**: Alias for readFrom.
*   **`writeTo(filename: str, file_text: Any, encode_codec: Optional[str] = None, v: bool = False) -> bool`**: Writes ASCII files.
*   **`writeToFile(filename: str, file_text: Any, encode_codec: Optional[str] = None, v: bool = False) -> bool`**: Alias for writeTo.
*   **`writeFile(filename: str, file_text: Any, encode_codec: Optional[str] = None, v: bool = False) -> bool`**: Alias for writeTo.

**Compression & Archives:**
*   **`compressTo7z(input_dir: str, output_file: str, compressionLevel: int = 4, excludeExt: Optional[list] = None, v: bool = False) -> None`**: Compresses a directory into a .7z file.
*   **`uncompress(inputFile: str, outputDir: str, v: bool = False) -> None`**: Extracts various archive formats (.7z, .zip, .tar, etc.).
*   **`uncompressFile(inputFile: str, outputDir: str, v: bool = False) -> None`**: Alias for uncompress.
*   **`unzipFile(inputFile: str, outputDir: str, v: bool = False) -> None`**: Alias for uncompress.
*   **`extractZip(inputFile: str, outputDir: str, v: bool = False) -> None`**: Alias for uncompress.
*   **`extractCompressedFile(inputFile: str, outputDir: str, v: bool = False) -> None`**: Alias for uncompress.

**File Monitoring & Statistics:**
*   **`fileCount(path: str = "./", extension: str = ".*", v: bool = True) -> int`**: Gets the number of files in a directory with a specific extension.
*   **`watchFileCount(path: str = "./", extension: str = ".*", interval: float = 0.2, duration = 3, v: bool = True) -> None`**: Monitors file count over time.

**Variable Persistence:**
*   **`pythonVariable(filename: str, option: str, variable: Any = None) -> Any`**: Saves ('dump') or loads ('load') Python variables using pickle.

**Download Operations:**
*   **`downloadFile(url: str, save_path: str, exists_action: str = 'resume', num_connections: int = 5, v: bool = False) -> None`**: Downloads files with resume and multi-connection support.
*   **`downloadChunk(url: str, start: int, end: int, path: str) -> None`**: Internal function for chunked downloads.

### Geospatial Data Processing (`ccfx.py`)

**Raster Operations:**
*   **`clipRasterByExtent(inFile: str, outFile: str, bounds: tuple) -> str`**: Clips a raster using bounding box coordinates.
*   **`clipRasterByVector(inFile: str, outFile: str, vectorFile: str) -> str`**: Clips a raster using a vector file.
*   **`resampleRaster(inFile: str, outFile: str, resolution: float, dstSRS = None, resamplingMethod = 'bilinear', replaceOutput: bool = True, v: bool = True) -> Optional[str]`**: Resamples a raster to a new resolution.
*   **`reprojectRaster(inFile: str, outFile: str, dstProjection: str, resamplingMethod: str = 'mode') -> str`**: Reprojects a raster to a new CRS.
*   **`mergeRasterTiles(tileList: list, outFile: str) -> str`**: Merges multiple raster files into one.
*   **`mergeRasterFiles(tileList: list, outFile: str) -> str`**: Alias for mergeRasterTiles.
*   **`rasterizeRaster(inFile: str, outFile: str, targetField: str, targetResolution: float) -> str`**: Rasterizes a vector layer based on an attribute field.
*   **`rasterizeGDF(gdf: geopandas.GeoDataFrame, valueField: str, outRasterFN: str, resolution: float, isCOG: bool = True, allTouched: bool = False, profileOverrides: dict | None = None) -> str`**: Rasterizes a GeoDataFrame to GeoTIFF/COG.
*   **`tiffWriteArray(array: numpy.ndarray, outputFile: str, geoTransform: tuple = (0, 1, 0, 0, 0, -1), projection: str = 'EPSG:4326', noData: Optional[float] = None, v: bool = False) -> gdal.Dataset`**: Writes a NumPy array to a GeoTIFF file.

**Vector Operations:**
*   **`clipVectorByExtent(inFile: str, outFile: str, bounds: tuple) -> str`**: Clips a vector file using bounding box coordinates.
*   **`clipFeatures(inputFeaturePath: str, boundaryFeature: str, outputFeature: str, keepOnlyTypes: Optional[list] = None, v: bool = False) -> geopandas.GeoDataFrame`**: Clips input features by a boundary feature.
*   **`getVectorBounds(grid_gdf: geopandas.GeoDataFrame) -> tuple`**: Gets the bounds of a GeoDataFrame.

**Coordinate & Geometry Operations:**
*   **`convertCoordinates(lon: float, lat: float, srcEPSG: str, dstCRS: str) -> tuple`**: Converts coordinates between CRSs.
*   **`extractRasterValue(rasterPath: str, lat: float, lon: float, coordProj: str = 'EPSG:4326') -> Optional[float]`**: Extracts the raster value at a specific point.
*   **`getRasterValue(rasterPath: str, lat: float, lon: float, coordProj: str = 'EPSG:4326') -> Optional[float]`**: Alias for extractRasterValue.
*   **`pointsToGeodataframe(rowList: list, columnNames: list, latIndex: int, lonIndex: int, auth: str = "EPSG", code: str = "4326", outShape: str = "", format: str = "gpkg", v: bool = False, includeLatLon: bool = True) -> geopandas.GeoDataFrame`**: Converts a list of point coordinates to a GeoDataFrame.
*   **`createPointGeometry(coords: list, proj: str = "EPSG:4326") -> geopandas.GeoDataFrame`**: Converts list of coordinate tuples to GeoDataFrame.
*   **`createGrid(topLeft: Optional[list] = None, bottomRight: Optional[list] = None, resolution: Optional[float] = None, inputShape: Optional[str] = None, crs: str = "EPSG:4326", saveVector: Optional[str] = None) -> geopandas.GeoDataFrame`**: Creates a grid of polygons based on shapefile or coordinates.
*   **`createPolygonFromOuterPoints(pointsGdf: geopandas.GeoDataFrame, alpha: float = 1.6, keepHoles: bool = False) -> geopandas.GeoDataFrame`**: Creates concave hull (alpha-shape) from points.

### NetCDF File Handling (`ccfx.py`)

*   **`netcdfVariablesList(ncFile: str) -> list`**: Lists variables in a NetCDF file.
*   **`netcdfVariableDimensions(ncFile: str, variable: str) -> dict`**: Gets dimensions and their sizes for a NetCDF variable.
*   **`netcdfExportTif(ncFile: str, variable: str, outputFile: Optional[str] = None, band: Optional[int] = None, v: bool = True) -> gdal.Dataset`**: Exports a NetCDF variable (optionally a specific band) to GeoTIFF.
*   **`netcdfAverageMap(ncFiles: list, variable: str, band: int = 1) -> numpy.ndarray`**: Calculates the average map from a variable across multiple NetCDF files.
*   **`netcdfSumMaps(ncFiles: list, variable: str, band: int = 1) -> numpy.ndarray`**: Calculates the sum map from a variable across multiple NetCDF files.
*   **`renameNetCDFvariable(input_file: str, output_file: str, old_var_name: str, new_var_name: str, v: bool = False) -> None`**: Renames a variable in a NetCDF file using CDO.
*   **`netCDFToTiff(srcFile: str, dstFile: str, variableName: str, timeStamp: object = None, v: bool = False) -> None`**: Converts a NetCDF to tiff

### Database Connectivity

#### MS SQL Server (`mssqlConnection.py`)
**Class: `mssqlConnection(server, username, password, driver, trust_server_ssl=True)`**
*   **`__init__(server, username, password, driver, trust_server_ssl=True) -> None`**: Initialize connection parameters.
*   **`connect()`**: Establish connection to server.
*   **`listDatabases() -> list`**: List available databases.
*   **`listTables(db_name=None) -> list`**: List tables in database.
*   **`readTable()`**: Read table data (including spatial data into GeoDataFrames).
*   **`connectDB()`**: Connect to specific database.
*   **`dataframeToSql()`**: Write DataFrame/GeoDataFrame to table.
*   **`dropTable()`**: Remove table.
*   **`close()`**: Close connection.

#### SQLite (`sqliteConnection.py`)
**Class: `sqliteConnection(sqlite_database, connect=False)`**
*   **`__init__(sqlite_database, connect=False) -> None`**: Initialize database connection.
*   **`connect(v=True) -> None`**: Establish connection.
*   **`createTable(table_name, initial_field_name, data_type) -> None`**: Create new table.
*   **`renameTable()`**: Rename existing table.
*   **`deleteTable()`**: Remove table.
*   **`readTableAsDict()`**: Read table data as dictionary.
*   **`insertDict()`**: Insert data from dictionary.
*   **`insertRow()`**: Insert single row.
*   **`updateValue(table_name, col_name, new_value, col_where1, val_1, v=False) -> None`**: Update specific values.
*   **`dumpCSV()`**: Export table to CSV.
*   **`commitChanges()`**: Commit transactions.
*   **`closeConnection()`**: Close connection.

### Document & Spreadsheet Generation

#### Excel Spreadsheets (`excel.py`)
**Class: `excel(path)`**
*   **`__init__(path)`**: Initialize Excel document.
*   **`create()`**: Create new workbook.
*   **`addSheet(sheet_name)`**: Add worksheet.
*   **`write(sheet_name, row, column, value)`**: Write data to cells.
*   **`writeDate(sheet_name, row, column, datetime_obj)`**: Write date values.
*   **`setDateFormat(format_string='dd/mm/yyyy')`**: Set date format.
*   **`setColumnWidth(sheet_name, column_names, width=12)`**: Adjust column widths.
*   **`addFigure(sheet_name, x_src_sheet_name, x_start, x_end, y_src_sheet_name, y_start, y_end, position_cell="E2", chart_type='subtype')`**: Insert charts/graphs.
*   **`save()`**: Save workbook.
*   **`open()`**: Open existing file.

#### Word Documents (`word.py`)
**Class: `word_document(path)`**
*   **`__init__(path) -> None`**: Initialize Word document.
*   **`addHeading(heading, level=2)`**: Add document headings.
*   **`addParagraph(text="", alignment='justify')`**: Add text paragraphs.
*   **`addListItem(text="", numbers=False)`**: Add list items.
*   **`addText(text, bold=False, italic=False)`**: Add formatted text.
*   **`addImage(path_to_image, width_=16)`**: Insert images.
*   **`addPageBreak()`**: Insert page breaks.
*   **`setMargins()`**: Configure page margins.
*   **`save()`**: Save document.

### Multimedia & Web (`ccfx.py`)

**MP3 Metadata:**
*   **`getMp3Metadata(fn: str, imagePath: Optional[str] = None) -> dict`**: Extracts ID3 metadata from an MP3 file.
*   **`setMp3Metadata(fn: str, metadata: dict, imagePath: Optional[str] = None) -> bool`**: Writes ID3 metadata (including album art) to an MP3 file.
*   **`guessMimeType(imagePath: str) -> str`**: Determines MIME type of image files.

**YouTube Downloads:**
*   **`downloadYoutubeVideo(url: str, dstDir: str, audioOnly: bool = False, cookiesFile: Optional[str] = None, dstFileName: Optional[str] = None) -> str`**: Downloads video or audio from a YouTube URL.
*   **`parseYoutubePlaylist(playlistUrl: str) -> list[str]`**: Returns list of video URLs from a YouTube playlist.
*   **`parseYoutubeChannelVideos(channelUrl: str, maxItems: Optional[int] = None) -> list[str]`**: Returns list of video URLs from a YouTube channel.

**Image Processing:**
*   **`removeImageColour(inPath: str, outPath: str, colour: tuple = (255, 255, 255), tolerance: int = 30) -> None`**: Removes a specific color from an image.
*   **`makeTransparent(inPath: str, outPath: str, colour: tuple = (255, 255, 255), tolerance: int = 30) -> None`**: Makes pixels in an image transparent.

**Video Processing:**
*   **`correctFisheye(inputFile: str, outputFile: str = '', k1: float = -0.1, k2: float = 0.05, cx: float = 0.5, cy: float = 0.5, crf: int = 20) -> str`**: Corrects fisheye distortion in videos.
*   **`correctLens(inputFile: str, outputFile: str = '', k1: float = -0.1, k2: float = 0.05, cx: float = 0.5, cy: float = 0.5, crf: int = 20) -> str`**: Alias for correctFisheye.

### Data Analysis & Statistics (`ccfx.py`)

**Timeseries Analysis:**
*   **`calculateTimeseriesStats(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> dict`**: Calculates comprehensive statistics between observed and simulated timeseries.
*   **`getNSE(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Nash-Sutcliffe Efficiency.
*   **`getKGE(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Kling-Gupta Efficiency.
*   **`getPBIAS(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Percent Bias.
*   **`getLNSE(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Log Nash-Sutcliffe Efficiency.
*   **`getR2(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates R-squared.
*   **`getRMSE(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Root Mean Square Error.
*   **`getMAE(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Mean Absolute Error.
*   **`getMSE(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> float`**: Calculates Mean Square Error.
*   **`getTimeseriesStats(data: pandas.DataFrame, observed: Optional[str] = None, simulated: Optional[str] = None, resample: Optional[str] = None) -> dict`**: Alias for calculateTimeseriesStats.

**SWAT+ Integration:**
*   **`readSWATPlusOutputs(filePath: str, column: Optional[str] = None, unit: Optional[int] = None, gis_id: Optional[int] = None, name: Optional[str] = None, coerceNumeric: bool = True) -> Optional[pandas.DataFrame]`**: Reads SWAT+ output files with filtering capabilities.
*   **`runSWATPlus(txtinoutDir: str, finalDir: str, executablePath: str = "swatplus", v: bool = True) -> None`**: Runs SWAT+ model with progress monitoring.

### Utility Functions (`ccfx.py`)

**Progress & Display:**
*   **`progressBar(count: int, total: int, message: str = "") -> None`**: Displays a simple console progress bar.
*   **`showProgress(count: int, end: int, message: str, barLength: int = 100) -> None`**: Displays a detailed console progress bar.
*   **`dualProgress(primaryCount: int, primaryEnd: int, secondaryCount: int, secondaryEnd: int, barLength: int = 40, message: str = '') -> None`**: Displays two progress bars simultaneously.

**System & Environment:**
*   **`systemPlatform() -> str`**: Gets the system platform.
*   **`setHomeDir(path: str) -> str`**: Sets the working directory to script location.
*   **`ignoreWarnings(ignore: bool = True, v: bool = False) -> None`**: Suppresses or enables Python warnings.

**Text & String Processing:**
*   **`formatStringBlock(input_str: str, max_chars: int = 70) -> str`**: Formats a string into a block of text with maximum characters per line.
*   **`formatTimedelta(delta: timedelta) -> str`**: Formats a timedelta duration to readable format.

**Mathematical Utilities:**
*   **`isBetween(number: float, a: float, b: float) -> bool`**: Returns True if number is between a and b.

**Notifications:**
*   **`alert(message: str, server: str = "http://ntfy.sh", topic: str = "pythonAlerts", attachment: Optional[str] = None, messageTitle: str = "info", priority: int = None, tags: list = [], printIt: bool = True, v: bool = False) -> bool`**: Sends notifications to external servers.

## Contributing

Contributions are welcome! Please fork the repository, make your changes, and submit a pull request. Ensure code is well-documented and includes tests where applicable.

### Development Setup
```bash
git clone https://github.com/celray/ccfx.git
cd ccfx
pip install -e .
```

### Version Management
To automatically update the version in README.md based on `pyproject.toml`:
```bash
# Make the script executable (if not already)
chmod +x updateReadmeVersion.py

# Run the version update script
./updateReadmeVersion.py
```

You can also integrate this into your build process by adding it to your CI/CD pipeline or as a pre-commit hook.

### Testing
Please ensure your changes don't break existing functionality and add tests for new features.

For detailed release notes, visit the [Releases page](https://github.com/celray/ccfx/releases).

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

**Author**: Celray James CHAWANDA  
**Email**: celray@chawanda.com  
**GitHub**: [@celray](https://github.com/celray)  
**Package Homepage**: [https://github.com/celray/ccfx](https://github.com/celray/ccfx)