Skip to content

Commit

Permalink
Merge pull request #31 from azogue/feature/pydantic-models
Browse files Browse the repository at this point in the history
♻️ Full re-work on internals to use pydantic models
  • Loading branch information
azogue authored Jun 5, 2023
2 parents ea00722 + 1292839 commit ec6b8dc
Show file tree
Hide file tree
Showing 41 changed files with 4,103 additions and 2,804 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,6 @@ fabric.properties

# Mac Os X files
**/.DS_Store

# generated plots in tests
tests/generated
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.0] - ♻️ Full re-work on internals to use pydantic models - 2023-06-05

🧹 Internal evolution to update the code style to the latest versions and de facto standards, with better typing, input validation, and serialization.
Hardly any new features, but some bug fixes.

### Changes

- 🏗️ Add [`pydantic`](https://docs.pydantic.dev/latest/) models for chart + annotations styling and config, for better (de)serialization and parameter validation.

New models are:

- `CurveStyle`, `LabelStyle`, `TickStyle`, `ZoneStyle` := to parse & handle defaults for matplotlib styling parameters
- `ChartConfig` for the full chart configuration, including sub-models `ChartFigure`, `ChartLimits`, and `ChartParams`, to mirror the old obfuscated config, with the same default values as before
- `ChartPoint` and `ChartSeries` for styled single-point or array-data annotations
- `ChartLine` for styled connectors between named points (now without outline 'marker' by default)
- `ChartArea` for styled convex areas delimited by a list of named points
- `ChartAnnots` as container for all of the above
- `ChartZone` (and `ChartZones` as a list), for styled fixed areas (like the default winter/summer comfort zones)

- ♻️ Evolve load methods to parse inputs into pydantic models with _near-zero_ (expected 🤞) breaks when reading old data
- 💥 Rework `PsychroChart` class to work with pydantic `PsychroChartModel`. As the chart is now a pydantic model, there is a `chart.json(...)` method, and loading from serialized data is available with `PsychroChart.parse_file(` / `.validate(` / etc 🤩
> **BREAKING-CHANGE**: Now the chart creation from a configuration key/file/dict is done with **`PsychroChart.create(config)`**, instead of old `PsychroChart(config)`
- ✨ Add `.make_svg()` method to produce a SVG file as text, and evolve `.save(...)` with optional `canvas_cls: Type[FigureCanvasBase]`, to select kind of matplotlib canvas where to print the chart
- ✨ Support file creation in subfolders with chart.save(dest)
- 🚚 rsc: Deterministic SVG output in tests, and README images without date metadata
- ✅ tests: Adapt API changes in unit tests, remove usages of `unittest.TestCase`, add new tests for pydantic models, annotations, and serialization methods.

## [0.4.0] - ♻️ Maintenance update to upgrade used libraries

### Changes
Expand Down
65 changes: 43 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ It implements a useful collection of psychrometric equations for moisture and hu

**Psychrometric calculations to make the chart data are done with [`PsychroLib`](https://github.com/psychrometrics/psychrolib)** (summary paper in https://doi.org/10.21105/joss.01137).

<img src="https://rawgit.com/azogue/psychrochart/master/tests/charts/chart_overlay_style_minimal.svg" width="100%" height="100%">
<img src="./tests/example-charts/chart_overlay_style_minimal.svg" width="100%" height="100%">

## Install

Get it **[from pypi](https://pypi.python.org/pypi?:action=display&name=psychrochart)** or **[clone it](https://github.com/azogue/psychrochart.git)** if you want to run the tests.

```bash
```shell
pip install psychrochart
```

## Features

- **SI** units (with temperatures in celsius for better readability).
- Easy style customization with a **JSON template** (colors, line styles and line widths).
- Easy style customization based on [**pydantic**](https://docs.pydantic.dev/latest/) models and config presets for full customization of colors, line styles, line widths, etc..
- Psychrometric charts within temperature and humidity ratio ranges, for any pressure\*, with:
- **Saturation line**
- **Constant RH lines**
Expand All @@ -43,29 +43,33 @@ pip install psychrochart
- **Constant humidity ratio lines** (internal orthogonal grid, horizontal)
- Plot legend for each family of lines
- Specify labels for each family of lines
- **Overlay points, zones, arrows...**
- **Overlay points, zones, convex hulls, and arrows**
- **Export SVG, PNG files**

\* The ranges of temperature, humidity and pressure where this library should provide good results are within the normal environments for people to live in. Don't expect right results if doing other type of thermodynamic calculations. Over saturated water vapor states are not implemented.
> NOTE: The ranges of temperature, humidity and pressure where this library should provide good results are within the normal environments for people to live in.
>
> Don't expect right results if doing other type of thermodynamic calculations.
>
> ⚠️ **Over saturated water vapor states are not implemented**. This library is intended for HVAC applications only ⚠️
## Usage

```python
from psychrochart import PsychroChart

# Load default style:
chart_default = PsychroChart()
chart_default = PsychroChart.create()
axes = chart_default.plot()
axes.get_figure()
```

Called from a terminal (`python psychrochart`), it plots and shows the default chart using the default matplotlib backend, equivalent to this python script:
Called from the terminal (`python psychrochart`), it plots and shows the default chart using the default matplotlib backend, equivalent to this python script:

```python
from psychrochart import PsychroChart
import matplotlib.pyplot as plt

PsychroChart().plot(ax=plt.gca())
PsychroChart.create().plot(ax=plt.gca())
plt.show()
```

Expand All @@ -75,20 +79,35 @@ The default styling for charts is defined in JSON files that you can change, or
Included styles are: `default`, `ashrae`, `interior` and `minimal`.

```python
from pathlib import Path
from psychrochart import load_config, PsychroChart

# Load preconfigured styles:
chart_ashrae_style = PsychroChart('ashrae')
chart_ashrae_style = PsychroChart.create('ashrae')
chart_ashrae_style.plot()

chart_minimal = PsychroChart('minimal')
chart_minimal = PsychroChart.create('minimal')
chart_minimal.plot()

# Get a preconfigured style dict
dict_config = load_config('interior')
# Get a preconfigured style model and customize it
chart_config = load_config('interior')
chart_config.limits.range_temp_c = (18.0, 32.0)
chart_config.limits.range_humidity_g_kg = (1.0, 40.0)
chart_config.limits.altitude_m = 3000

custom_chart = PsychroChart.create(chart_config)
custom_chart.save("custom-chart.svg")

# serialize the config for future uses
assert chart_config.json() == custom_chart.config.json()
Path('path/to/chart_config_file.json').write_text(chart_config.json())
custom_chart_bis = PsychroChart.create('path/to/chart_config_file.json')
# or even the full psychrochart
Path('path/to/chart_file.json').write_text(custom_chart.json())
custom_chart_bis_2 = PsychroChart.parse_file('path/to/chart_file.json')

# Specify the styles JSON file:
chart_custom = PsychroChart('/path/to/json_file.json')
chart_custom = PsychroChart.create('/path/to/json_file.json')
chart_custom.plot()

# Pass a dict with the changes wanted:
Expand Down Expand Up @@ -121,18 +140,20 @@ custom_style = {
}
}

chart_custom_2 = PsychroChart(custom_style)
chart_custom_2 = PsychroChart.create(custom_style)
chart_custom_2.plot()
```

The custom configuration does not need to include all fields, but only the fields you want to change.

To play with it and see the results, look at this **[notebook with usage examples](https://github.com/azogue/psychrochart/blob/master/notebooks/Usage%20example%20of%20psychrochart.ipynb)**.

## Tests
## Development and testing

To run the tests, clone the repository, `poetry install` it, and run `poetry run pytest`.

Run `poetry run pre-commit run --all-files` to apply linters for changes in the code 😜.

## License

[MIT license](https://github.com/azogue/psychrochart/blob/master/LICENSE), so do with it as you like ;-)
Expand All @@ -141,16 +162,16 @@ To run the tests, clone the repository, `poetry install` it, and run `poetry run

**Default style**:

<img src="https://rawgit.com/azogue/psychrochart/master/tests/charts/test_default_psychrochart.svg" width="100%" height="100%">
<img src="./tests/example-charts/test_default_psychrochart.svg" width="100%" height="100%">

**ASHRAE Handbook black and white style**:
**ASHRAE Handbook black and white style**: (preset: `ashrae`)

<img src="https://rawgit.com/azogue/psychrochart/master/tests/charts/test_ashrae_psychrochart.svg" width="100%" height="100%">
<img src="./tests/example-charts/test_ashrae_psychrochart.svg" width="100%" height="100%">

**ASHRAE Handbook black and white style (IP units)**:
**ASHRAE Handbook black and white style (IP units)**: (preset: `ashrae_ip`)

<img src="https://rawgit.com/azogue/psychrochart/master/tests/charts/test_ashrae_psychrochart_ip.svg" width="100%" height="100%">
<img src="./tests/example-charts/test_ashrae_psychrochart_ip.svg" width="100%" height="100%">

**Minimal style**:
**Minimal style**: (preset: `minimal`)

<img src="https://rawgit.com/azogue/psychrochart/master/tests/charts/test_minimal_psychrochart.svg" width="100%" height="100%">
<img src="./tests/example-charts/test_minimal_psychrochart.svg" width="100%" height="100%">
65 changes: 64 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 18 additions & 4 deletions psychrochart/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
# -*- coding: utf-8 -*-
"""A library to make psychrometric charts and overlay information in them."""
from .chart import PsychroChart
from .psychrocurves import PsychroCurve, PsychroCurves
from .util import load_config, load_zones
from psychrochart.chart import PsychroChart
from psychrochart.models.annots import ChartAnnots, ChartZones
from psychrochart.models.config import ChartConfig
from psychrochart.models.curves import PsychroCurve, PsychroCurves
from psychrochart.models.parsers import load_config, load_zones
from psychrochart.models.styles import (
CurveStyle,
LabelStyle,
TickStyle,
ZoneStyle,
)

__all__ = [
"ChartAnnots",
"ChartConfig",
"ChartZones",
"load_config",
"load_zones",
"PsychroChart",
"PsychroCurve",
"PsychroCurves",
"CurveStyle",
"LabelStyle",
"TickStyle",
"ZoneStyle",
]
3 changes: 1 addition & 2 deletions psychrochart/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""A library to make psychrometric charts and overlay information in them."""
import matplotlib.pyplot as plt

Expand All @@ -7,7 +6,7 @@

def main():
"""CLI entry point to show the default psychrometric chart."""
PsychroChart().plot(ax=plt.gca())
PsychroChart.create().plot(ax=plt.gca())


if __name__ == "__main__":
Expand Down
1 change: 0 additions & 1 deletion psychrochart/agg.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
A python library to make psychrometric charts and overlay information in them.
Expand Down
Loading

0 comments on commit ec6b8dc

Please sign in to comment.