kopia lustrzana https://github.com/sepandhaghighi/samila
Porównaj commity
69 Commity
Autor | SHA1 | Data |
---|---|---|
Sepand Haghighi | 6316e17d83 | |
Sadra Sabouri | 2a98624138 | |
dependabot[bot] | a994902006 | |
dependabot[bot] | 74128ba966 | |
Sepand Haghighi | be973ee183 | |
Sadra Sabouri | a54a5107a5 | |
dependabot[bot] | e3c9cede8c | |
omahs | 74c36df546 | |
Sepand Haghighi | 773b89aac9 | |
dependabot[bot] | 3452354cd0 | |
Sepand Haghighi | 54abe440af | |
Sadra Sabouri | a9e23235b2 | |
Sepand Haghighi | 7e66936dc2 | |
sepandhaghighi | 54d58497ef | |
Sepand Haghighi | b38deb26c3 | |
dependabot[bot] | 9fb12259e0 | |
Sadra Sabouri | 36085c761b | |
Sepand Haghighi | 539547a7c1 | |
Sadra Sabouri | f21f82c225 | |
Sepand Haghighi | b8967acc28 | |
Sepand Haghighi | a2729fb9ab | |
Sepand Haghighi | 5be1cc35fc | |
dependabot[bot] | 3d1005185f | |
Sadra Sabouri | 27317de6c8 | |
dependabot[bot] | daeafed59f | |
Sepand Haghighi | 9f32c783c9 | |
dependabot[bot] | 3d361a466c | |
Sepand Haghighi | e42f80847d | |
sepandhaghighi | a65cea3549 | |
Sepand Haghighi | a7a1ae56ee | |
Sepand Haghighi | 2fadfea62f | |
Sepand Haghighi | 2717332d85 | |
Sepand Haghighi | d9224cd6fc | |
Sadra Sabouri | 750d126bd6 | |
dependabot[bot] | c254e0cfd8 | |
Sadra Sabouri | d67d69c9dd | |
dependabot[bot] | 9c6fbeafeb | |
Sepand Haghighi | fc2dbd0db9 | |
Sepand Haghighi | 66d2c788d0 | |
Sepand Haghighi | 73f8fe8ce0 | |
Sepand Haghighi | f3de359440 | |
sepandhaghighi | c1dc35ec6a | |
Sadra Sabouri | 819792d832 | |
Sadra Sabouri | fd80f431ef | |
Sepand Haghighi | 6007ab4c16 | |
dependabot[bot] | 4de5e89b03 | |
Sepand Haghighi | df9cf76f34 | |
Sepand Haghighi | eda38916f6 | |
Sepand Haghighi | 8cb4f6b369 | |
sepandhaghighi | 9d47fe596c | |
Sepand Haghighi | e6d40bf681 | |
Sepand Haghighi | e0cc52f74c | |
Sadra Sabouri | d2b7585b1a | |
Sepand Haghighi | 7444b9bd90 | |
dependabot[bot] | 32c13ec0cb | |
Sadra Sabouri | ca7c676d12 | |
sepandhaghighi | d298cf0a56 | |
sepandhaghighi | aad63fc7b9 | |
sepandhaghighi | dac8ca3fa0 | |
Sadra Sabouri | b6558c5cd7 | |
Sepand Haghighi | 168759083c | |
Sepand Haghighi | 841862f8da | |
Sepand Haghighi | e3adb4659b | |
sepandhaghighi | 2c4a3676f3 | |
Sepand Haghighi | a179ff45b2 | |
Sepand Haghighi | 37527f2cdb | |
Sadra Sabouri | 24cec90e9e | |
Sadra Sabouri | 4f25f846f8 | |
Evan Slack | 7fd4f9123c |
|
@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
|
|||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at info@4r7.ir. All
|
||||
reported by contacting the project team at info@samila.site. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
name: publish_conda
|
||||
|
||||
on:
|
||||
push:
|
||||
# Sequence of patterns matched against refs/tags
|
||||
tags:
|
||||
- '*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: publish-to-conda
|
||||
uses: sepandhaghighi/conda-package-publish-action@v1.2
|
||||
with:
|
||||
subDir: 'otherfiles'
|
||||
AnacondaToken: ${{ secrets.ANACONDA_TOKEN }}
|
|
@ -11,8 +11,8 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
python-version: [3.5, 3.6, 3.7, 3.8, 3.9, 3.10.0]
|
||||
os: [ubuntu-20.04, windows-latest]
|
||||
python-version: [3.5, 3.6, 3.7, 3.8, 3.9, 3.10.0, 3.11.0]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
|
@ -40,23 +40,26 @@ jobs:
|
|||
python -m pytest test --cov=samila --cov-report=term
|
||||
env:
|
||||
NFT_STORAGE_API_KEY: ${{ secrets.NFT_STORAGE_API_KEY }}
|
||||
if: matrix.python-version == 3.7 && matrix.os == 'ubuntu-latest'
|
||||
if: matrix.python-version == 3.8 && matrix.os == 'ubuntu-20.04'
|
||||
- name: Version check
|
||||
run: |
|
||||
python otherfiles/version_check.py
|
||||
if: matrix.python-version == 3.7
|
||||
if: matrix.python-version == 3.8
|
||||
- name: Other tests
|
||||
run: |
|
||||
python -m vulture samila/ setup.py --min-confidence 65 --exclude=__init__.py --sort-by-size
|
||||
python -m bandit -r samila -s B311,B307
|
||||
python -m pydocstyle -v --match-dir=samila
|
||||
if: matrix.python-version == 3.7
|
||||
if: matrix.python-version == 3.8
|
||||
- name: Notebook check
|
||||
run: |
|
||||
pip install notebook>=5.2.2
|
||||
python otherfiles/notebook_check.py
|
||||
if: matrix.python-version == 3.7 && matrix.os == 'ubuntu-latest'
|
||||
if: matrix.python-version == 3.8 && matrix.os == 'ubuntu-20.04'
|
||||
- name: Codecov
|
||||
run: |
|
||||
codecov
|
||||
if: matrix.python-version == 3.7 && matrix.os == 'ubuntu-latest'
|
||||
if: matrix.python-version == 3.8 && matrix.os == 'ubuntu-20.04'
|
||||
- name: cProfile
|
||||
run: |
|
||||
python -m cProfile -s cumtime otherfiles/samila_profile.py
|
||||
|
|
99
CHANGELOG.md
99
CHANGELOG.md
|
@ -5,6 +5,95 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## [1.1] - 2023-04-05
|
||||
### Added
|
||||
- `__version__` attribute
|
||||
- `python_version` attribute
|
||||
- `get_python_version` function
|
||||
- `RANDOM_EQUATION_MIN_COMPLEXITY` parameter
|
||||
- `RANDOM_EQUATION_FOF_MAX_DEPTH` parameter
|
||||
- `RANDOM_EQUATION_FOF_MIN_DEPTH` parameter
|
||||
- `rotate` function
|
||||
### Changed
|
||||
- `rotation` parameter added to `plot` method
|
||||
- `timeout` parameter added to `nft_storage` method
|
||||
- `load_config` function modified
|
||||
- `nft_storage_upload` function modified
|
||||
- Random mode modified
|
||||
- `RANDOM_EQUATION_GEN_COMPLEXITY` parameter renamed to `RANDOM_EQUATION_MAX_COMPLEXITY`
|
||||
- `README.md` updated
|
||||
## [1.0] - 2022-12-14
|
||||
### Added
|
||||
- `Marker` enum
|
||||
- `get_data` function
|
||||
- `get_config` function
|
||||
### Changed
|
||||
- `marker` parameter added to `plot` method
|
||||
- `upload_data` parameter added to `nft_storage` method
|
||||
- `upload_config` parameter added to `nft_storage` method
|
||||
- `generate` method optimized
|
||||
- Test system modified
|
||||
- `README.md` updated
|
||||
- `Python 3.11` added to `test.yml`
|
||||
- `plot` method warning bug fixed
|
||||
- Random mode modified
|
||||
### Removed
|
||||
- `fill_data` function
|
||||
## [0.9] - 2022-09-28
|
||||
### Added
|
||||
- Anaconda workflow
|
||||
### Changed
|
||||
- `README.md` updated
|
||||
- `CODE_OF_CONDUCT.md` updated
|
||||
- `demo.ipynb` updated
|
||||
- `cmap` parameter added to `plot` method
|
||||
- Random mode modified
|
||||
- Test system modified
|
||||
- `generate` method optimized
|
||||
- `samila_help` function updated
|
||||
- `load_data` and `load_config` functions error handling updated
|
||||
## [0.8] - 2022-06-01
|
||||
### Added
|
||||
- `INVALID_COLOR_TYPE_ERROR` error
|
||||
- `COLOR_NOT_FOUND_WARNING` warning
|
||||
- `BOTH_COLOR_COMPLEMENT_WARNING` warning
|
||||
- `set_background` function
|
||||
- `is_valid_color` function
|
||||
- `color_complement` function
|
||||
- `select_color` function
|
||||
### Changed
|
||||
- Transparent mode support for `bgcolor` parameter
|
||||
- Random mode modified
|
||||
- Complementary color support for `color` and `bgcolor` parameters
|
||||
- `filter_color` function modified
|
||||
## [0.7] - 2022-05-04
|
||||
### Added
|
||||
- `fill_data` function
|
||||
- `random_hex_color_gen` function
|
||||
- `color`,`bgcolor` and `projection` parameters random mode
|
||||
### Changed
|
||||
- Calculation warning added to `generate` method
|
||||
- Hex color support for `color` and `bgcolor` parameters
|
||||
- Test system modified
|
||||
- Random mode modified
|
||||
- `filter_color` function modified
|
||||
- `filter_projection` function modified
|
||||
- `is_same_data` function modified
|
||||
- `README.md` updated
|
||||
## [0.6] - 2022-04-13
|
||||
### Added
|
||||
- `save_params_filter` function
|
||||
### Changed
|
||||
- `__del__` method updated
|
||||
- `message` field changed in `save_fig_file` function
|
||||
- `message` field changed in `save_config_file` function
|
||||
- `message` field changed in `save_data_file` function
|
||||
- `message` field changed in `nft_storage_upload` function
|
||||
- `depth` section added to config/data file
|
||||
- `linewidth` parameter added to `plot` method
|
||||
- `linewidth` parameter added to `plot_params_filter` function
|
||||
- Random mode modified
|
||||
- `README.md` updated
|
||||
## [0.5] - 2022-03-21
|
||||
### Added
|
||||
- `__del__` method
|
||||
|
@ -50,7 +139,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- `save_data_file` function
|
||||
- `save_data` method
|
||||
### Changed
|
||||
- `data` parameter added to GenerativeImage `__init__`
|
||||
- `data` parameter added to GenerativeImage `__init__` method
|
||||
- `depth` parameter added to `save_image` method
|
||||
- `depth` parameter added to `save_fig_file` function
|
||||
- `save_image` and `nft_storage` methods background bug fixed
|
||||
|
@ -81,7 +170,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- `generate` method
|
||||
- `nft_storage` method
|
||||
|
||||
[Unreleased]: https://github.com/sepandhaghighi/samila/compare/v0.5...dev
|
||||
[Unreleased]: https://github.com/sepandhaghighi/samila/compare/v1.1...dev
|
||||
[1.1]: https://github.com/sepandhaghighi/samila/compare/v1.0...v1.1
|
||||
[1.0]: https://github.com/sepandhaghighi/samila/compare/v0.9...v1.0
|
||||
[0.9]: https://github.com/sepandhaghighi/samila/compare/v0.8...v0.9
|
||||
[0.8]: https://github.com/sepandhaghighi/samila/compare/v0.7...v0.8
|
||||
[0.7]: https://github.com/sepandhaghighi/samila/compare/v0.6...v0.7
|
||||
[0.6]: https://github.com/sepandhaghighi/samila/compare/v0.5...v0.6
|
||||
[0.5]: https://github.com/sepandhaghighi/samila/compare/v0.4...v0.5
|
||||
[0.4]: https://github.com/sepandhaghighi/samila/compare/v0.3...v0.4
|
||||
[0.3]: https://github.com/sepandhaghighi/samila/compare/v0.2...v0.3
|
||||
|
|
127
README.md
127
README.md
|
@ -8,6 +8,7 @@
|
|||
<img src="https://codecov.io/gh/sepandhaghighi/samila/branch/master/graph/badge.svg" />
|
||||
</a>
|
||||
<a href="https://badge.fury.io/py/samila"><img src="https://badge.fury.io/py/samila.svg" alt="PyPI version" height="18"></a>
|
||||
<a href="https://anaconda.org/sepandhaghighi/samila"><img src="https://anaconda.org/sepandhaghighi/samila/badges/version.svg"></a>
|
||||
<a href="https://colab.research.google.com/github/sepandhaghighi/samila/blob/master">
|
||||
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Samila-Colab"/>
|
||||
</a>
|
||||
|
@ -24,10 +25,10 @@
|
|||
* [Mathematical Details](https://github.com/sepandhaghighi/samila#mathematical-details)
|
||||
* [Try Samila in Your Browser](https://github.com/sepandhaghighi/samila#try-samila-in-your-browser)
|
||||
* [Issues & Bug Reports](https://github.com/sepandhaghighi/samila#issues--bug-reports)
|
||||
* [Dependencies](https://github.com/sepandhaghighi/samila#dependencies)
|
||||
* [Social Media](https://github.com/sepandhaghighi/samila#social-media)
|
||||
* [Contribution](https://github.com/sepandhaghighi/samila/blob/master/.github/CONTRIBUTING.md)
|
||||
* [References](https://github.com/sepandhaghighi/samila#references)
|
||||
* [Acknowledgments](https://github.com/sepandhaghighi/samila#acknowledgments)
|
||||
* [Authors](https://github.com/sepandhaghighi/samila/blob/master/AUTHORS.md)
|
||||
* [License](https://github.com/sepandhaghighi/samila/blob/master/LICENSE)
|
||||
* [Show Your Support](https://github.com/sepandhaghighi/samila#show-your-support)
|
||||
|
@ -37,7 +38,7 @@
|
|||
## Overview
|
||||
|
||||
<p align="justify">
|
||||
Samila is a generative art generator written in Python, Samila let's you create arts based on many thousand points. The position of every single point is calculated by a formula, which has random parameters. Because of the random numbers, every image looks different.
|
||||
Samila is a generative art generator written in Python, Samila lets you create images based on many thousand points. The position of every single point is calculated by a formula, which has random parameters. Because of the random numbers, every image looks different.
|
||||
</p>
|
||||
|
||||
|
||||
|
@ -87,7 +88,7 @@ Samila is a generative art generator written in Python, Samila let's you create
|
|||
|
||||
|
||||
### Source code
|
||||
- Download [Version 0.5](https://github.com/sepandhaghighi/samila/archive/v0.5.zip) or [Latest Source ](https://github.com/sepandhaghighi/samila/archive/dev.zip)
|
||||
- Download [Version 1.1](https://github.com/sepandhaghighi/samila/archive/v1.1.zip) or [Latest Source](https://github.com/sepandhaghighi/samila/archive/dev.zip)
|
||||
- Run `pip install -r requirements.txt` or `pip3 install -r requirements.txt` (Need root access)
|
||||
- Run `python3 setup.py install` or `python setup.py install` (Need root access)
|
||||
|
||||
|
@ -95,12 +96,17 @@ Samila is a generative art generator written in Python, Samila let's you create
|
|||
|
||||
|
||||
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
||||
- Run `pip install samila==0.5` or `pip3 install samila==0.5` (Need root access)
|
||||
- Run `pip install samila==1.1` or `pip3 install samila==1.1` (Need root access)
|
||||
|
||||
### Easy install
|
||||
|
||||
- Run `easy_install --upgrade samila` (Need root access)
|
||||
|
||||
### Conda
|
||||
|
||||
- Check [Conda Managing Package](https://conda.io)
|
||||
- `conda install -c sepandhaghighi samila` (Need root access)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -146,9 +152,35 @@ Samila is a generative art generator written in Python, Samila let's you create
|
|||
```
|
||||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/images/2.png">
|
||||
|
||||
* Supported projections : `RECTILINEAR`, `POLAR`, `AITOFF`, `HAMMER`, `LAMBERT` and `MOLLWEIDE`
|
||||
* Supported projections : `RECTILINEAR`, `POLAR`, `AITOFF`, `HAMMER`, `LAMBERT`, `MOLLWEIDE` and `RANDOM`
|
||||
* Default projection is `RECTILINEAR`
|
||||
|
||||
### Marker
|
||||
```pycon
|
||||
>>> from samila import Marker
|
||||
>>> g = GenerativeImage(f1, f2)
|
||||
>>> g.generate()
|
||||
>>> g.plot(marker=Marker.CIRCLE, spot_size=10)
|
||||
>>> g.seed
|
||||
448742
|
||||
>>> plt.show()
|
||||
```
|
||||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/images/9.png">
|
||||
|
||||
* Supported markers : `POINT`, `PIXEL`, `CIRCLE`, `TRIANGLE_DOWN`, `TRIANGLE_UP`, `TRIANGLE_LEFT`, `TRIANGLE_RIGHT`, `TRI_DOWN`, `TRI_UP`, `TRI_LEFT`, `TRI_RIGHT`, `OCTAGON`, `SQUARE`, `PENTAGON`, `PLUS`, `PLUS_FILLED`, `STAR`, `HEXAGON_VERTICAL`, `HEXAGON_HORIZONTAL`, `X`, `X_FILLED`, `DIAMOND`, `DIAMON_THIN`, `VLINE`, `HLINE` and `RANDOM`
|
||||
* Default marker is `POINT`
|
||||
|
||||
### Rotation
|
||||
You can even rotate your art by using `rotation` parameter. Enter your desired rotation for the image in degrees and you will have it.
|
||||
|
||||
```pycon
|
||||
>>> g = GenerativeImage(f1, f2)
|
||||
>>> g.generate()
|
||||
>>> g.plot(rotation=45)
|
||||
```
|
||||
|
||||
* Default rotation is 0
|
||||
|
||||
### Range
|
||||
```pycon
|
||||
>>> g = GenerativeImage(f1, f2)
|
||||
|
@ -172,7 +204,41 @@ Samila is a generative art generator written in Python, Samila let's you create
|
|||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/images/4.png">
|
||||
|
||||
* Supported colors are available in `VALID_COLORS` list
|
||||
* `color` and `bgcolor` parameters support color name and RGB/RGBA formats
|
||||
* `color` and `bgcolor` parameters supported formats:
|
||||
|
||||
1. Color name (example: `color="yellow"`)
|
||||
2. RGB/RGBA (example: `color=(0.1,0.1,0.1)`, `color=(0.1,0.1,0.1,0.1)`)
|
||||
3. Hex (example: `color="#eeefff"`)
|
||||
4. Random (example: `color="random"`)
|
||||
5. Complement (example: `color="complement", bgcolor="blue"`)
|
||||
6. Transparent (example: `bgcolor="transparent"`)
|
||||
7. List (example: `color=["black", "#fffeef",...]`)
|
||||
|
||||
⚠️ **Transparent** mode is only available for background
|
||||
|
||||
⚠️ **List** mode is only available for color
|
||||
|
||||
⚠️ In **List** mode, the length of this list must be equal to the lengths of data1 and data2
|
||||
|
||||
#### Point Color
|
||||
You can make your custom color map and use it in Samila
|
||||
|
||||
```pycon
|
||||
>>> colorarray = [
|
||||
... [0.7, 0.2, 0.2, 1],
|
||||
... [0.6, 0.3, 0.2, 1],
|
||||
... "black",
|
||||
... [0.4, 0.4, 0.3, 1],
|
||||
... [0.3, 0.4, 0.4, 1],
|
||||
... "#ff2561"]
|
||||
>>> g.generate()
|
||||
>>> g.seed
|
||||
454893
|
||||
>>> g.plot(cmap=colorarray, color=g.data2, projection=Projection.POLAR)
|
||||
>>> plt.show()
|
||||
```
|
||||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/images/8.png">
|
||||
|
||||
|
||||
### Regeneration
|
||||
```pycon
|
||||
|
@ -187,22 +253,35 @@ Samila is a generative art generator written in Python, Samila let's you create
|
|||
Upload generated image directly to [NFT.storage](https://NFT.storage)
|
||||
|
||||
```pycon
|
||||
>>> g.nft_storage(api_key="YOUR_API_KEY")
|
||||
{'status': True, 'message': 'Everything seems good'}
|
||||
>>> g.nft_storage(api_key="YOUR_API_KEY", timeout=5000)
|
||||
{'status': True, 'message': 'FILE_LINK'}
|
||||
```
|
||||
|
||||
You can also upload your config/data to nft storage as follows:
|
||||
```pycon
|
||||
>>> g.nft_storage(api_key="API_KEY", upload_config=True)
|
||||
{'status': {'image': True, 'config':True}, 'message': {'image':'IMAGE_FILE_LINK', 'config':'CONFIG_FILE_LINK'}
|
||||
```
|
||||
or
|
||||
```pycon
|
||||
>>> g.nft_storage(api_key="API_KEY", upload_data=True)
|
||||
{'status': {'image': True, 'data':True}, 'message': {'image':'IMAGE_FILE_LINK', 'data':'DATA_FILE_LINK'}
|
||||
```
|
||||
|
||||
* Default timeout is **3000** seconds
|
||||
|
||||
### Save image
|
||||
Save generated image
|
||||
|
||||
```pycon
|
||||
>>> g.save_image(file_adr="test.png")
|
||||
{'status': True, 'message': 'Everything seems good'}
|
||||
{'status': True, 'message': 'FILE_PATH'}
|
||||
```
|
||||
Save generated image in higher resolutions
|
||||
|
||||
```pycon
|
||||
>>> g.save_image(file_adr="test.png", depth=5)
|
||||
{'status': True, 'message': 'Everything seems good'}
|
||||
{'status': True, 'message': 'FILE_PATH'}
|
||||
```
|
||||
|
||||
### Save data
|
||||
|
@ -210,6 +289,7 @@ Save generated image data
|
|||
|
||||
```pycon
|
||||
>>> g.save_data(file_adr="data.json")
|
||||
{'status': True, 'message': 'FILE_PATH'}
|
||||
```
|
||||
So you can load it into a `GenerativeImage` instance later by
|
||||
|
||||
|
@ -247,6 +327,7 @@ Save generated image config. It contains string formats of functions which is al
|
|||
|
||||
```pycon
|
||||
>>> g.save_config(file_adr="config.json")
|
||||
{'status': True, 'message': 'FILE_PATH'}
|
||||
```
|
||||
So you can load it into a `GenerativeImage` instance later by
|
||||
|
||||
|
@ -282,11 +363,11 @@ Samila is simply a transformation between a square-shaped space from the Cartesi
|
|||
### Example
|
||||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/mathematical_details/transformation.png">
|
||||
|
||||
We have set of points in the first space (left square) which can be define as follow:
|
||||
We have set of points in the first space (left square) which can be defined as follow:
|
||||
|
||||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/mathematical_details/S1.jpg">
|
||||
|
||||
And bellow functions are used for transformation:
|
||||
And below functions are used for transformation:
|
||||
|
||||
```pycon
|
||||
>>> def f1(x, y):
|
||||
|
@ -299,7 +380,7 @@ And bellow functions are used for transformation:
|
|||
|
||||
<img src="https://github.com/sepandhaghighi/samila/raw/master/otherfiles/mathematical_details/S2.jpg">
|
||||
|
||||
here we uses `Projection.POLAR` so later space will be the polar space and we have:
|
||||
here we use `Projection.POLAR` so later space will be the polar space and we have:
|
||||
|
||||
```pycon
|
||||
>>> g = GenerativeImage(f1, f2)
|
||||
|
@ -321,7 +402,7 @@ Samila can be used online in interactive Jupyter Notebooks via the Binder or Col
|
|||
|
||||
## Issues & bug reports
|
||||
|
||||
Just fill an issue and describe it. We'll check it ASAP!
|
||||
Just fill an issue and describe it. We'll check it ASAP! or send an email to [info@samila.site](mailto:info@samila.site "info@samila.site").
|
||||
|
||||
- Please complete the issue template
|
||||
|
||||
|
@ -332,19 +413,6 @@ You can also join our discord server
|
|||
</a>
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">master</td>
|
||||
<td align="center">dev</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://requires.io/github/sepandhaghighi/samila/requirements/?branch=master"><img src="https://requires.io/github/sepandhaghighi/samila/requirements.svg?branch=master" alt="Requirements Status" /></a></td>
|
||||
<td align="center"><a href="https://requires.io/github/sepandhaghighi/samila/requirements/?branch=dev"><img src="https://requires.io/github/sepandhaghighi/samila/requirements.svg?branch=dev" alt="Requirements Status" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Social media
|
||||
|
||||
1. [Instagram](https://www.instagram.com/samila_arts)
|
||||
|
@ -360,7 +428,10 @@ You can also join our discord server
|
|||
<blockquote>2- <a href="https://github.com/cutterkom/generativeart">Create Generative Art with R</a></blockquote>
|
||||
|
||||
<blockquote>3- <a href="https://nft.storage/">NFT.storage : Free decentralized storage and bandwidth for NFTs</a></blockquote>
|
||||
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
This project was funded through the **Next Step Microgrant**, a program established by [Protocol Labs](https://protocol.ai/).
|
||||
|
||||
## Show your support
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
python -m autopep8 samila --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --verbose
|
||||
python -m autopep8 samila --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --verbose --ignore=E721
|
||||
python -m autopep8 setup.py --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --verbose
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/bin/sh
|
||||
python -m autopep8 samila --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --verbose
|
||||
python -m autopep8 samila --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --verbose --ignore=E721
|
||||
python -m autopep8 setup.py --recursive --aggressive --aggressive --in-place --pep8-passes 2000 --verbose
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
matplotlib==3.5.1
|
||||
art==5.5
|
||||
matplotlib==3.7.1
|
||||
art==5.9
|
||||
vulture>=1.0
|
||||
bandit>=1.5.1
|
||||
pydocstyle>=3.0.0
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"import matplotlib.pyplot as plt\n",
|
||||
"import random\n",
|
||||
"import math\n",
|
||||
"from samila import GenerativeImage, Projection"
|
||||
"from samila import GenerativeImage, Projection, Marker"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -88,7 +88,7 @@
|
|||
"## Projection\n",
|
||||
"We can use the `projection` attribute to define the coordinate system to transform our functions\n",
|
||||
"\n",
|
||||
"The avaliable projections are `RECTILINEAR`, `POLAR`, `AITOFF`, `HAMMER`, `LAMBERT` and `MOLLWEIDE`"
|
||||
"The avaliable projections are `RECTILINEAR`, `POLAR`, `AITOFF`, `HAMMER`, `LAMBERT`, `MOLLWEIDE` and `RANDOM`"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -107,6 +107,53 @@
|
|||
" plt.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Marker\n",
|
||||
"We can use the `marker` attribute to change the plotting marker.\n",
|
||||
"\n",
|
||||
"The available markers are `POINT`, `PIXEL`, `CIRCLE`, `TRIANGLE_DOWN`, `TRIANGLE_UP`, `TRIANGLE_LEFT`, `TRIANGLE_RIGHT`, `TRI_DOWN`, `TRI_UP`, `TRI_LEFT`, `TRI_RIGHT`, `OCTAGON`, `SQUARE`, `PENTAGON`, `PLUS`, `PLUS_FILLED`, `STAR`, `HEXAGON_VERTICAL`, `HEXAGON_HORIZONTAL`, `X`, `X_FILLED`, `DIAMOND`, `DIAMON_THIN`, `VLINE`, `HLINE` and `RANDOM`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"g2 = GenerativeImage(f1, f2)\n",
|
||||
"g2.generate()\n",
|
||||
"\n",
|
||||
"for m in list(Marker):\n",
|
||||
" print(m)\n",
|
||||
" g2.plot(marker=m, spot_size=100)\n",
|
||||
" plt.show()\n",
|
||||
" plt.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Rotation\n",
|
||||
"You can even rotate your art by using `rotation` parameter. Enter your desired rotation for the image in degrees and you will have it.\n",
|
||||
"\n",
|
||||
"* Default rotation is 0."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"g = GenerativeImage(f1, f2)\n",
|
||||
"g.generate()\n",
|
||||
"g.plot(rotation=45)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
@ -134,9 +181,7 @@
|
|||
"source": [
|
||||
"## Color\n",
|
||||
"\n",
|
||||
"We can assign colors for both the background as well as the line\n",
|
||||
"\n",
|
||||
"Supported colors are available in `VALID_COLORS` list\n"
|
||||
"We can assign colors for both the background as well as the line\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -151,6 +196,55 @@
|
|||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"* Supported colors are available in `VALID_COLORS` list\n",
|
||||
"* `color` and `bgcolor` parameters supported formats:\n",
|
||||
"\n",
|
||||
" 1. Color name (example: `color=\"yellow\"`)\n",
|
||||
" 2. RGB/RGBA (example: `color=(0.1,0.1,0.1)`, `color=(0.1,0.1,0.1,0.1)`)\n",
|
||||
" 3. Hex (example: `color=\"#eeefff\"`)\n",
|
||||
" 4. Random (example: `color=\"random\"`)\n",
|
||||
" 5. Complement (example: `color=\"complement\", bgcolor=\"blue\"`)\n",
|
||||
" 6. Transparent (example: `bgcolor=\"transparent\"`)\n",
|
||||
" 7. List (example: `color=[\"black\", \"#fffeef\",...]`)\n",
|
||||
"\n",
|
||||
"⚠️ **Transparent** mode is only available for background\n",
|
||||
"\n",
|
||||
"⚠️ **List** mode is only available for color\n",
|
||||
"\n",
|
||||
"⚠️ In **List** mode, the length of this list must be equal to the lengths of data1 and data2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Point Color\n",
|
||||
"\n",
|
||||
"You can make your custom color map and use it in Samila"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"colorarray = [\n",
|
||||
" [0.7, 0.2, 0.2, 1],\n",
|
||||
" [0.6, 0.3, 0.2, 1],\n",
|
||||
" \"black\",\n",
|
||||
" [0.4, 0.4, 0.3, 1],\n",
|
||||
" [0.3, 0.4, 0.4, 1],\n",
|
||||
" \"#ff2561\"]\n",
|
||||
"g2.generate()\n",
|
||||
"g2.plot(cmap=colorarray, color=g2.data2, projection=Projection.POLAR)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
@ -316,6 +410,47 @@
|
|||
"source": [
|
||||
"g1.nft_storage(api_key=\"YOUR_API_KEY\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"g1.nft_storage(api_key=\"YOUR_API_KEY\", timeout=5000)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also upload your config/data to nft storage as follows:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"g1.nft_storage(api_key=\"YOUR_API_KEY\", upload_config=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"g1.nft_storage(api_key=\"YOUR_API_KEY\", upload_data=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"* Default timeout is **3000** seconds"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
@ -335,6 +470,29 @@
|
|||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.5.2"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": false,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": true,
|
||||
"title_cell": "Samila Demo",
|
||||
"title_sidebar": "Samila Demo",
|
||||
"toc_cell": false,
|
||||
"toc_position": {
|
||||
"height": "382px",
|
||||
"left": "10px",
|
||||
"top": "10px",
|
||||
"width": "256px"
|
||||
},
|
||||
"toc_section_display": false,
|
||||
"toc_window_display": true
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 403 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 169 KiB |
|
@ -0,0 +1,37 @@
|
|||
{% set name = "samila" %}
|
||||
{% set version = "1.1" %}
|
||||
|
||||
package:
|
||||
name: {{ name|lower }}
|
||||
version: {{ version }}
|
||||
source:
|
||||
git_url: https://github.com/sepandhaghighi/samila
|
||||
git_rev: v{{ version }}
|
||||
build:
|
||||
noarch: python
|
||||
number: 0
|
||||
script: {{ PYTHON }} -m pip install . -vv
|
||||
requirements:
|
||||
host:
|
||||
- pip
|
||||
- setuptools
|
||||
- python >=3.5
|
||||
run:
|
||||
- art >=1.8
|
||||
- matplotlib >=3.0.0
|
||||
- requests >=2.20.0
|
||||
- python >=3.5
|
||||
about:
|
||||
home: https://github.com/sepandhaghighi/samila
|
||||
license: MIT
|
||||
license_family: MIT
|
||||
summary: Generative Art Generator
|
||||
description: |
|
||||
Samila is a generative art generator written in Python, Samila let's you create arts based on many thousand points. The position of every single point is calculated by a formula, which has random parameters. Because of the random numbers, every image looks different.
|
||||
|
||||
Website: https://www.samila.site
|
||||
|
||||
Repo: https://github.com/sepandhaghighi/samila
|
||||
extra:
|
||||
recipe-maintainers:
|
||||
- sepandhaghighi
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Samila profile."""
|
||||
from samila import *
|
||||
import random
|
||||
import math
|
||||
|
||||
|
||||
def f1(x, y):
|
||||
result = random.uniform(-1, 1) * x**2 - math.sin(y**2) + abs(y-x)
|
||||
return result
|
||||
|
||||
|
||||
def f2(x, y):
|
||||
result = random.uniform(-1, 1) * y**3 - math.cos(x**2) + 2*x
|
||||
return result
|
||||
|
||||
g = GenerativeImage(f1, f2)
|
||||
g.generate(seed=200)
|
||||
g.plot()
|
||||
g.save_image("test.png")
|
|
@ -4,7 +4,7 @@ import os
|
|||
import sys
|
||||
import codecs
|
||||
Failed = 0
|
||||
SAMILA_VERSION = "0.5"
|
||||
SAMILA_VERSION = "1.1"
|
||||
|
||||
|
||||
SETUP_ITEMS = [
|
||||
|
@ -19,9 +19,12 @@ CHANGELOG_ITEMS = [
|
|||
"https://github.com/sepandhaghighi/samila/compare/v{0}...dev",
|
||||
"[{0}]:"]
|
||||
PARAMS_ITEMS = ['SAMILA_VERSION = "{0}"']
|
||||
|
||||
META_ITEMS = ['% set version = "{0}" %']
|
||||
|
||||
FILES = {
|
||||
"setup.py": SETUP_ITEMS, "README.md": README_ITEMS, "CHANGELOG.md": CHANGELOG_ITEMS, os.path.join(
|
||||
"samila", "params.py"): PARAMS_ITEMS}
|
||||
"samila", "params.py"): PARAMS_ITEMS, os.path.join("otherfiles", "meta.yaml"): META_ITEMS}
|
||||
|
||||
TEST_NUMBER = len(FILES.keys())
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
matplotlib>=3.0.0
|
||||
requests>=2.20.0
|
||||
art>=1.8
|
||||
Pillow>=6.2
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Samila modules."""
|
||||
from .genimage import GenerativeImage
|
||||
from .params import Projection, VALID_COLORS, SAMILA_VERSION
|
||||
from .params import Projection, Marker, VALID_COLORS, SAMILA_VERSION
|
||||
from .errors import samilaDataError, samilaGenerateError
|
||||
__version__ = SAMILA_VERSION
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Samila functions."""
|
||||
|
||||
import sys
|
||||
import requests
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import random
|
||||
import matplotlib
|
||||
from .params import DEFAULT_START, DEFAULT_STOP, DEFAULT_STEP, DEFAULT_COLOR, DEFAULT_IMAGE_SIZE
|
||||
from .params import DEFAULT_BACKGROUND_COLOR, DEFAULT_SPOT_SIZE, DEFAULT_PROJECTION, DEFAULT_ALPHA
|
||||
from .params import Projection, VALID_COLORS, NFT_STORAGE_API, OVERVIEW
|
||||
from .params import DATA_TYPE_ERROR, CONFIG_TYPE_ERROR, PLOT_DATA_ERROR, CONFIG_NO_STR_FUNCTION_ERROR
|
||||
from matplotlib import cm
|
||||
from matplotlib.colors import ListedColormap
|
||||
from PIL import Image
|
||||
from .params import SAMILA_VERSION
|
||||
from .params import DEFAULT_MARKER, DEFAULT_START, DEFAULT_STOP, DEFAULT_STEP, DEFAULT_COLOR, DEFAULT_IMAGE_SIZE, DEFAULT_DEPTH
|
||||
from .params import DEFAULT_CMAP, DEFAULT_CMAP_RANGE, DEFAULT_ROTATION
|
||||
from .params import DEFAULT_BACKGROUND_COLOR, DEFAULT_SPOT_SIZE, DEFAULT_PROJECTION, DEFAULT_ALPHA, DEFAULT_LINEWIDTH
|
||||
from .params import Projection, Marker, VALID_COLORS, HEX_COLOR_PATTERN, NFT_STORAGE_API, NFT_STORAGE_LINK, OVERVIEW
|
||||
from .params import DATA_TYPE_ERROR, DATA_FORMAT_ERROR, CONFIG_TYPE_ERROR, CONFIG_FORMAT_ERROR, PLOT_DATA_ERROR, CONFIG_NO_STR_FUNCTION_ERROR
|
||||
from .params import NO_FIG_ERROR_MESSAGE, FIG_SAVE_SUCCESS_MESSAGE, NFT_STORAGE_SUCCESS_MESSAGE, SAVE_NO_DATA_ERROR
|
||||
from .params import INVALID_COLOR_TYPE_ERROR, COLOR_SIZE_ERROR
|
||||
from .params import BOTH_COLOR_COMPLEMENT_WARNING, COLOR_NOT_FOUND_WARNING
|
||||
from .params import DATA_SAVE_SUCCESS_MESSAGE, SEED_LOWER_BOUND, SEED_UPPER_BOUND
|
||||
from .params import ELEMENTS_LIST, ARGUMENTS_LIST, OPERATORS_LIST
|
||||
from .params import ELEMENTS_LIST, ARGUMENTS_LIST, OPERATORS_LIST, RANDOM_COEF_LIST
|
||||
from .params import RANDOM_EQUATION_MIN_COMPLEXITY, RANDOM_EQUATION_MAX_COMPLEXITY, RANDOM_EQUATION_FOF_MIN_DEPTH, RANDOM_EQUATION_FOF_MAX_DEPTH
|
||||
from .errors import samilaDataError, samilaPlotError, samilaConfigError
|
||||
from warnings import warn
|
||||
|
||||
|
||||
def random_equation_gen():
|
||||
|
@ -22,20 +34,38 @@ def random_equation_gen():
|
|||
|
||||
:return: equation as str
|
||||
"""
|
||||
num_elements = random.randint(2, len(ELEMENTS_LIST) + 3)
|
||||
num_elements = random.randint(
|
||||
RANDOM_EQUATION_MIN_COMPLEXITY,
|
||||
RANDOM_EQUATION_MAX_COMPLEXITY)
|
||||
result = ""
|
||||
index = 1
|
||||
random_coef = "random.uniform(-1,1)"
|
||||
random_coef = random.choice(RANDOM_COEF_LIST)
|
||||
while(index <= num_elements):
|
||||
argument = random.choice(ARGUMENTS_LIST)
|
||||
result = result + \
|
||||
random.choice(ELEMENTS_LIST).format(random_coef, argument)
|
||||
element = random.choice(ARGUMENTS_LIST)
|
||||
fof_depth = random.randint(
|
||||
RANDOM_EQUATION_FOF_MIN_DEPTH,
|
||||
RANDOM_EQUATION_FOF_MAX_DEPTH)
|
||||
for _ in range(fof_depth):
|
||||
element = random.choice(ELEMENTS_LIST).format(random_coef, element)
|
||||
result = result + element
|
||||
if index < num_elements:
|
||||
result = result + random.choice(OPERATORS_LIST)
|
||||
index = index + 1
|
||||
if random.randint(0, 1) == 1:
|
||||
result = random.choice(ELEMENTS_LIST).format(random_coef, result)
|
||||
return result
|
||||
|
||||
|
||||
def random_hex_color_gen():
|
||||
"""
|
||||
Generate random hex color code.
|
||||
|
||||
:return: color code as str
|
||||
"""
|
||||
random_color = "#%06x" % random.randint(0, 0xFFFFFF)
|
||||
return random_color
|
||||
|
||||
|
||||
def float_range(start, stop, step):
|
||||
"""
|
||||
Generate float range.
|
||||
|
@ -83,22 +113,137 @@ def distance_calc(s1, s2):
|
|||
return distances[-1]
|
||||
|
||||
|
||||
def filter_color(color):
|
||||
def is_valid_color(color):
|
||||
"""
|
||||
Filter given color and return it.
|
||||
Check that input color format is valid or not.
|
||||
|
||||
:param color: given color
|
||||
:type color: str or tuple
|
||||
:return: filtered version of color
|
||||
:type color: any format
|
||||
:return: result as bool
|
||||
"""
|
||||
if color is None:
|
||||
return True
|
||||
try:
|
||||
_ = matplotlib.colors.to_hex(color)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
def color_complement(color):
|
||||
"""
|
||||
Calculate complement color.
|
||||
|
||||
:param color: given color (hex format)
|
||||
:type color: str
|
||||
:return: complement color (hex format) as str
|
||||
"""
|
||||
color = color[1:]
|
||||
color = int(color, 16)
|
||||
comp_color = 0xFFFFFF ^ color
|
||||
comp_color = "#%06x" % comp_color
|
||||
return comp_color
|
||||
|
||||
|
||||
def filter_color(color, bgcolor):
|
||||
"""
|
||||
Filter given color and bgcolor.
|
||||
|
||||
:param color: given color
|
||||
:type color: any format
|
||||
:param bgcolor: given background color
|
||||
:type bgcolor: any format
|
||||
:return: filtered version of color and bgcolor
|
||||
"""
|
||||
color = select_color(color)
|
||||
bgcolor = select_color(bgcolor)
|
||||
if color == "COMPLEMENT" and bgcolor == "COMPLEMENT":
|
||||
warn(BOTH_COLOR_COMPLEMENT_WARNING, RuntimeWarning)
|
||||
return None, None
|
||||
if color == "COMPLEMENT":
|
||||
bgcolor = matplotlib.colors.to_hex(bgcolor)
|
||||
color = color_complement(bgcolor)
|
||||
if bgcolor == "COMPLEMENT":
|
||||
color = matplotlib.colors.to_hex(color)
|
||||
bgcolor = color_complement(color)
|
||||
return color, bgcolor
|
||||
|
||||
|
||||
def filter_cmap(cmap):
|
||||
"""
|
||||
Filter given cmap.
|
||||
|
||||
:param cmap: color map
|
||||
:type cmap: matplotlib.colors.Colormap or list of colors
|
||||
:return: filtered version of cmap
|
||||
"""
|
||||
if isinstance(cmap, str):
|
||||
cmap = cm.get_cmap(cmap, 256)
|
||||
if type(cmap) == matplotlib.colors.Colormap:
|
||||
cmap = cm.get_cmap(cmap.__getattribute__("name"))
|
||||
if isinstance(cmap, matplotlib.colors.ListedColormap):
|
||||
return cmap
|
||||
if isinstance(cmap, (matplotlib.colors.LinearSegmentedColormap)):
|
||||
cmap = cmap(range(DEFAULT_CMAP_RANGE))
|
||||
return ListedColormap(cmap)
|
||||
if isinstance(cmap, list):
|
||||
cmap = list(map(select_color, cmap))
|
||||
return ListedColormap(cmap)
|
||||
return None
|
||||
|
||||
|
||||
def select_color(color):
|
||||
"""
|
||||
Select color and return it.
|
||||
|
||||
:param color: given color
|
||||
:type color: any format
|
||||
:return: color
|
||||
"""
|
||||
if isinstance(color, tuple):
|
||||
return color
|
||||
if isinstance(color, str):
|
||||
if color.upper() == "TRANSPARENT":
|
||||
return "TRANSPARENT"
|
||||
if color.upper() == "COMPLEMENT":
|
||||
return "COMPLEMENT"
|
||||
if color.upper() == "RANDOM":
|
||||
return random_hex_color_gen()
|
||||
if re.match(HEX_COLOR_PATTERN, color):
|
||||
return color.lower()
|
||||
distance_list = list(map(lambda x: distance_calc(color, x),
|
||||
VALID_COLORS))
|
||||
min_distance = min(distance_list)
|
||||
return VALID_COLORS[distance_list.index(min_distance)]
|
||||
return None
|
||||
most_similar_color = VALID_COLORS[distance_list.index(min_distance)]
|
||||
if min_distance != 0:
|
||||
warn(
|
||||
COLOR_NOT_FOUND_WARNING.format(
|
||||
color,
|
||||
most_similar_color),
|
||||
RuntimeWarning)
|
||||
return most_similar_color
|
||||
if is_valid_color(color):
|
||||
return color
|
||||
raise samilaPlotError(INVALID_COLOR_TYPE_ERROR)
|
||||
|
||||
|
||||
def set_background(bgcolor, fig, ax):
|
||||
"""
|
||||
Set background for figure and axis.
|
||||
|
||||
:param bgcolor: given background color
|
||||
:type bgcolor: any format
|
||||
:param fig: figure
|
||||
:type fig: matplotlib.figure.Figure
|
||||
:param ax: axis
|
||||
:type ax: matplotlib.axes._subplots.AxesSubplot
|
||||
:return: None
|
||||
"""
|
||||
if bgcolor == "TRANSPARENT":
|
||||
ax.patch.set_visible(False)
|
||||
fig.patch.set_visible(False)
|
||||
return
|
||||
fig.set_facecolor(bgcolor)
|
||||
ax.set_facecolor(bgcolor)
|
||||
return
|
||||
|
||||
|
||||
def filter_projection(projection):
|
||||
|
@ -110,7 +255,30 @@ def filter_projection(projection):
|
|||
:return: filtered version of projection
|
||||
"""
|
||||
if isinstance(projection, Projection):
|
||||
return projection.value
|
||||
projection_value = projection.value
|
||||
if projection_value == "random":
|
||||
projection_list = list(Projection)
|
||||
projection_list.remove(Projection.RANDOM)
|
||||
projection_value = random.choice(projection_list).value
|
||||
return projection_value
|
||||
return None
|
||||
|
||||
|
||||
def filter_marker(marker):
|
||||
"""
|
||||
Filter given marker.
|
||||
|
||||
:param marker: given marker
|
||||
:type marker: Marker enum
|
||||
:return: filtered version of marker
|
||||
"""
|
||||
if isinstance(marker, Marker):
|
||||
marker_value = marker.value
|
||||
if marker_value == "random":
|
||||
marker_list = list(Marker)
|
||||
marker_list.remove(Marker.RANDOM)
|
||||
marker_value = random.choice(marker_list).value
|
||||
return marker_value
|
||||
return None
|
||||
|
||||
|
||||
|
@ -141,14 +309,42 @@ def filter_size(size):
|
|||
return None
|
||||
|
||||
|
||||
def rotate(fig, ax, rotation):
|
||||
"""
|
||||
Rotate the given figure and return axis.
|
||||
|
||||
:param fig: figure containing the image
|
||||
:type fig: Figure
|
||||
:param ax: axis on which rotated image is ploted
|
||||
:type ax: Axis
|
||||
:param rotation: desired rotation (in degrees)
|
||||
:type rotation: float
|
||||
:return: axis containing rotated image
|
||||
"""
|
||||
if rotation != DEFAULT_ROTATION:
|
||||
buf = io.BytesIO()
|
||||
fig.savefig(buf, format='png')
|
||||
ax.cla()
|
||||
with Image.open(buf) as im:
|
||||
ax.imshow(im.rotate(rotation))
|
||||
ax.set_axis_off()
|
||||
ax.patch.set_zorder(-1)
|
||||
ax.add_artist(ax.patch)
|
||||
return ax
|
||||
|
||||
|
||||
def plot_params_filter(
|
||||
g,
|
||||
color=None,
|
||||
bgcolor=None,
|
||||
cmap=None,
|
||||
spot_size=None,
|
||||
size=None,
|
||||
projection=None,
|
||||
alpha=None):
|
||||
marker=None,
|
||||
alpha=None,
|
||||
linewidth=None,
|
||||
rotation=None):
|
||||
"""
|
||||
Filter plot method parameters.
|
||||
|
||||
|
@ -158,38 +354,63 @@ def plot_params_filter(
|
|||
:type color: str
|
||||
:param bgcolor: background color
|
||||
:type bgcolor: str
|
||||
:param cmap: color map
|
||||
:type cmap: matplotlib.colors.Colormap or list of colors
|
||||
:param spot_size: point spot size
|
||||
:type spot_size: float
|
||||
:param size: figure size
|
||||
:type size: tuple
|
||||
:param projection: projection type
|
||||
:type projection: str
|
||||
:param marker: marker type
|
||||
:type marker: str
|
||||
:param alpha: point transparency
|
||||
:type alpha: float
|
||||
:param linewidth: width of line
|
||||
:type linewidth: float
|
||||
:param rotation: desired rotation (in degrees)
|
||||
:type rotation: float
|
||||
:return: None
|
||||
"""
|
||||
if g.data1 is None:
|
||||
raise samilaPlotError(PLOT_DATA_ERROR.format(1))
|
||||
if g.data2 is None:
|
||||
raise samilaPlotError(PLOT_DATA_ERROR.format(2))
|
||||
color, bgcolor = map(filter_color, [color, bgcolor])
|
||||
if isinstance(color, list):
|
||||
if len(color) != len(g.data1):
|
||||
raise samilaPlotError(COLOR_SIZE_ERROR)
|
||||
bgcolor = select_color(bgcolor)
|
||||
else:
|
||||
color, bgcolor = filter_color(color, bgcolor)
|
||||
cmap = filter_cmap(cmap)
|
||||
projection = filter_projection(projection)
|
||||
marker = filter_marker(marker)
|
||||
alpha = filter_float(alpha)
|
||||
linewidth = filter_float(linewidth)
|
||||
spot_size = filter_float(spot_size)
|
||||
size = filter_size(size)
|
||||
if color is None:
|
||||
color = g.color
|
||||
if bgcolor is None:
|
||||
bgcolor = g.bgcolor
|
||||
if cmap is None:
|
||||
cmap = g.cmap
|
||||
if spot_size is None:
|
||||
spot_size = g.spot_size
|
||||
if size is None:
|
||||
size = g.size
|
||||
if projection is None:
|
||||
projection = g.projection
|
||||
if marker is None:
|
||||
marker = g.marker
|
||||
if alpha is None:
|
||||
alpha = g.alpha
|
||||
g.color, g.bgcolor, g.spot_size, g.size, g.projection, g.alpha = color, bgcolor, spot_size, size, projection, alpha
|
||||
if linewidth is None:
|
||||
linewidth = g.linewidth
|
||||
if rotation is None:
|
||||
rotation = g.rotation
|
||||
g.color, g.bgcolor, g.cmap, g.spot_size, g.size, g.projection, g.marker, g.alpha, g.linewidth, g.rotation = \
|
||||
color, bgcolor, cmap, spot_size, size, projection, marker, alpha, linewidth, rotation
|
||||
|
||||
|
||||
def generate_params_filter(
|
||||
|
@ -227,6 +448,19 @@ def generate_params_filter(
|
|||
g.seed, g.start, g.step, g.stop = seed, start, step, stop
|
||||
|
||||
|
||||
def save_params_filter(g, depth=None):
|
||||
"""
|
||||
Filter save_image method parameters.
|
||||
|
||||
:param depth: depth of image
|
||||
:type depth: float
|
||||
:return: None
|
||||
"""
|
||||
if depth is None:
|
||||
depth = g.depth
|
||||
g.depth = depth
|
||||
|
||||
|
||||
def _GI_initializer(g, function1, function2):
|
||||
"""
|
||||
Initialize the generative image.
|
||||
|
@ -239,7 +473,9 @@ def _GI_initializer(g, function1, function2):
|
|||
:type function2: python or lambda function
|
||||
:return: None
|
||||
"""
|
||||
g.__version__ = SAMILA_VERSION
|
||||
g.matplotlib_version = matplotlib.__version__
|
||||
g.python_version = get_python_version()
|
||||
g.function1 = function1
|
||||
g.function1_str = None
|
||||
g.function2 = function2
|
||||
|
@ -253,13 +489,19 @@ def _GI_initializer(g, function1, function2):
|
|||
g.data2 = None
|
||||
g.color = DEFAULT_COLOR
|
||||
g.bgcolor = DEFAULT_BACKGROUND_COLOR
|
||||
g.cmap = DEFAULT_CMAP
|
||||
g.spot_size = DEFAULT_SPOT_SIZE
|
||||
g.size = DEFAULT_IMAGE_SIZE
|
||||
g.projection = DEFAULT_PROJECTION
|
||||
g.marker = DEFAULT_MARKER
|
||||
g.alpha = DEFAULT_ALPHA
|
||||
g.linewidth = DEFAULT_LINEWIDTH
|
||||
g.rotation = DEFAULT_ROTATION
|
||||
g.depth = DEFAULT_DEPTH
|
||||
g.missed_points_number = 0
|
||||
|
||||
|
||||
def nft_storage_upload(api_key, data):
|
||||
def nft_storage_upload(api_key, data, timeout):
|
||||
"""
|
||||
Upload file to nft.storage.
|
||||
|
||||
|
@ -267,6 +509,8 @@ def nft_storage_upload(api_key, data):
|
|||
:type api_key: str
|
||||
:param data: image data
|
||||
:type data: binary
|
||||
:param timeout: upload timeout (in seconds)
|
||||
:type timeout: int
|
||||
:return: result as dict
|
||||
"""
|
||||
result = {"status": True, "message": NFT_STORAGE_SUCCESS_MESSAGE}
|
||||
|
@ -275,9 +519,12 @@ def nft_storage_upload(api_key, data):
|
|||
response = requests.post(
|
||||
url=NFT_STORAGE_API,
|
||||
data=data,
|
||||
headers=headers)
|
||||
headers=headers,
|
||||
timeout=timeout)
|
||||
response_json = response.json()
|
||||
if response_json["ok"]:
|
||||
result["message"] = NFT_STORAGE_LINK.format(
|
||||
response_json['value']['cid'])
|
||||
return result
|
||||
result["status"] = False
|
||||
result["message"] = response_json["error"]["message"]
|
||||
|
@ -298,7 +545,38 @@ def save_data_file(g, file_adr):
|
|||
:type file_adr: str
|
||||
:return: result as dict
|
||||
"""
|
||||
matplotlib_version = matplotlib.__version__
|
||||
data = get_data(g)
|
||||
result = {"status": True, "message": DATA_SAVE_SUCCESS_MESSAGE}
|
||||
try:
|
||||
with open(file_adr, 'w') as fp:
|
||||
json.dump(data, fp)
|
||||
result["message"] = os.path.abspath(file_adr)
|
||||
except Exception as e:
|
||||
result["status"] = False
|
||||
result["message"] = str(e)
|
||||
return result
|
||||
|
||||
|
||||
def get_python_version():
|
||||
"""
|
||||
Get Python's version.
|
||||
|
||||
:return: python's version as 'major.minor'
|
||||
"""
|
||||
return "{}.{}".format(
|
||||
sys.version_info.major,
|
||||
sys.version_info.minor
|
||||
)
|
||||
|
||||
|
||||
def get_data(g):
|
||||
"""
|
||||
Return data.
|
||||
|
||||
:param g: generative image instance
|
||||
:type g: GenerativeImage
|
||||
:return: data as a dict
|
||||
"""
|
||||
data = {}
|
||||
if g.data1 is None or g.data2 is None:
|
||||
raise samilaDataError(SAVE_NO_DATA_ERROR)
|
||||
|
@ -307,19 +585,56 @@ def save_data_file(g, file_adr):
|
|||
data['plot'] = {
|
||||
"color": g.color,
|
||||
"bgcolor": g.bgcolor,
|
||||
"cmap": _serialize_cmap(g.cmap),
|
||||
"spot_size": g.spot_size,
|
||||
"projection": g.projection,
|
||||
"alpha": g.alpha
|
||||
"marker": g.marker,
|
||||
"alpha": g.alpha,
|
||||
"linewidth": g.linewidth,
|
||||
"depth": g.depth,
|
||||
"rotation": g.rotation,
|
||||
}
|
||||
data['matplotlib_version'] = matplotlib_version
|
||||
result = {"status": True, "message": DATA_SAVE_SUCCESS_MESSAGE}
|
||||
try:
|
||||
with open(file_adr, 'w') as fp:
|
||||
json.dump(data, fp)
|
||||
except Exception as e:
|
||||
result["status"] = False
|
||||
result["message"] = str(e)
|
||||
return result
|
||||
data['matplotlib_version'] = g.matplotlib_version
|
||||
data['python_version'] = g.python_version
|
||||
data['__version__'] = g.__version__
|
||||
return data
|
||||
|
||||
|
||||
def get_config(g):
|
||||
"""
|
||||
Return config.
|
||||
|
||||
:param g: generative image instance
|
||||
:type g: GenerativeImage
|
||||
:return: config as a dict
|
||||
"""
|
||||
config = {}
|
||||
if g.function1_str is None or g.function2_str is None:
|
||||
raise samilaConfigError(CONFIG_NO_STR_FUNCTION_ERROR)
|
||||
config['f1'] = g.function1_str
|
||||
config['f2'] = g.function2_str
|
||||
config['generate'] = {
|
||||
"seed": g.seed,
|
||||
"start": g.start,
|
||||
"step": g.step,
|
||||
"stop": g.stop
|
||||
}
|
||||
config['plot'] = {
|
||||
"color": g.color,
|
||||
"bgcolor": g.bgcolor,
|
||||
"cmap": _serialize_cmap(g.cmap),
|
||||
"spot_size": g.spot_size,
|
||||
"projection": g.projection,
|
||||
"marker": g.marker,
|
||||
"alpha": g.alpha,
|
||||
"linewidth": g.linewidth,
|
||||
"depth": g.depth,
|
||||
"rotation": g.rotation,
|
||||
}
|
||||
config['matplotlib_version'] = g.matplotlib_version
|
||||
config['python_version'] = g.python_version
|
||||
config['__version__'] = g.__version__
|
||||
return config
|
||||
|
||||
|
||||
def save_config_file(g, file_adr):
|
||||
|
@ -332,30 +647,12 @@ def save_config_file(g, file_adr):
|
|||
:type file_adr: str
|
||||
:return: result as dict
|
||||
"""
|
||||
matplotlib_version = matplotlib.__version__
|
||||
data = {}
|
||||
if g.function1_str is None or g.function2_str is None:
|
||||
raise samilaConfigError(CONFIG_NO_STR_FUNCTION_ERROR)
|
||||
data['f1'] = g.function1_str
|
||||
data['f2'] = g.function2_str
|
||||
data['generate'] = {
|
||||
"seed": g.seed,
|
||||
"start": g.start,
|
||||
"step": g.step,
|
||||
"stop": g.stop
|
||||
}
|
||||
data['plot'] = {
|
||||
"color": g.color,
|
||||
"bgcolor": g.bgcolor,
|
||||
"spot_size": g.spot_size,
|
||||
"projection": g.projection,
|
||||
"alpha": g.alpha
|
||||
}
|
||||
data['matplotlib_version'] = matplotlib_version
|
||||
config = get_config(g)
|
||||
result = {"status": True, "message": DATA_SAVE_SUCCESS_MESSAGE}
|
||||
try:
|
||||
with open(file_adr, 'w') as fp:
|
||||
json.dump(data, fp, indent=4)
|
||||
json.dump(config, fp, indent=4)
|
||||
result["message"] = os.path.abspath(file_adr)
|
||||
except Exception as e:
|
||||
result["status"] = False
|
||||
result["message"] = str(e)
|
||||
|
@ -383,6 +680,7 @@ def save_fig_file(figure, file_adr, depth):
|
|||
dpi=depth * figure.dpi,
|
||||
facecolor=figure.get_facecolor(),
|
||||
edgecolor='none')
|
||||
result["message"] = os.path.abspath(file_adr)
|
||||
return result
|
||||
except Exception as e:
|
||||
result["status"] = False
|
||||
|
@ -429,6 +727,7 @@ def samila_help():
|
|||
:return: None
|
||||
"""
|
||||
print(OVERVIEW)
|
||||
print("Website : https://www.samila.site")
|
||||
print("Repo : https://github.com/sepandhaghighi/samila")
|
||||
|
||||
|
||||
|
@ -444,10 +743,50 @@ def is_same_data(data1, data2, precision=10**-5):
|
|||
:type precision: float
|
||||
:return: True if they are the same
|
||||
"""
|
||||
if len(data1) != len(data2):
|
||||
return False
|
||||
is_same = map(lambda x, y: abs(x - y) < precision, data1, data2)
|
||||
return all(is_same)
|
||||
|
||||
|
||||
def _serialize_color(color):
|
||||
"""
|
||||
Serialize the given color to a json serializable object.
|
||||
|
||||
:param color: given color
|
||||
:type color: str or nd.array
|
||||
:return: the serializable version of the color
|
||||
"""
|
||||
if isinstance(color, str):
|
||||
return color
|
||||
return list(color)
|
||||
|
||||
|
||||
def _serialize_cmap(cmap):
|
||||
"""
|
||||
Serialize the cmap for saving.
|
||||
|
||||
:param cmap: color map
|
||||
:type cmap: matplotlib.colors.Colormap
|
||||
:return: list of colors
|
||||
"""
|
||||
return list(map(_serialize_color, cmap.colors))
|
||||
|
||||
|
||||
def _load_cmap(config):
|
||||
"""
|
||||
Load the cmap from config.
|
||||
|
||||
:param config: plot part configuration
|
||||
:type config: dict or json
|
||||
:return: ListedColormap from cmap
|
||||
"""
|
||||
if "cmap" not in config:
|
||||
return DEFAULT_CMAP
|
||||
cmap = config["cmap"]
|
||||
return ListedColormap(cmap)
|
||||
|
||||
|
||||
def load_data(g, data):
|
||||
"""
|
||||
Load data file.
|
||||
|
@ -462,15 +801,26 @@ def load_data(g, data):
|
|||
data = json.load(data)
|
||||
g.data1 = data.get('data1')
|
||||
g.data2 = data.get('data2')
|
||||
if g.data1 is None or g.data2 is None:
|
||||
raise samilaDataError(DATA_FORMAT_ERROR)
|
||||
if 'matplotlib_version' in data:
|
||||
g.matplotlib_version = data['matplotlib_version']
|
||||
if 'python_version' in data:
|
||||
g.python_version = data['python_version']
|
||||
if '__version__' in data:
|
||||
g.__version__ = data['__version__']
|
||||
plot_config = data.get("plot")
|
||||
if plot_config is not None:
|
||||
g.color = plot_config.get("color", DEFAULT_COLOR)
|
||||
g.bgcolor = plot_config.get("bgcolor", DEFAULT_BACKGROUND_COLOR)
|
||||
g.cmap = _load_cmap(plot_config)
|
||||
g.spot_size = plot_config.get("spot_size", DEFAULT_SPOT_SIZE)
|
||||
g.projection = plot_config.get("projection", DEFAULT_PROJECTION)
|
||||
g.marker = plot_config.get("marker", DEFAULT_MARKER)
|
||||
g.alpha = plot_config.get("alpha", DEFAULT_ALPHA)
|
||||
g.linewidth = plot_config.get("linewidth", DEFAULT_LINEWIDTH)
|
||||
g.depth = plot_config.get("depth", DEFAULT_DEPTH)
|
||||
g.rotation = plot_config.get("rotation", DEFAULT_ROTATION)
|
||||
return
|
||||
raise samilaDataError(DATA_TYPE_ERROR)
|
||||
|
||||
|
@ -486,23 +836,34 @@ def load_config(g, config):
|
|||
:return: None
|
||||
"""
|
||||
if isinstance(config, io.IOBase):
|
||||
data = json.load(config)
|
||||
g.function1_str = data.get("f1")
|
||||
g.function2_str = data.get("f2")
|
||||
if 'matplotlib_version' in data:
|
||||
g.matplotlib_version = data['matplotlib_version']
|
||||
generate_config = data.get("generate")
|
||||
config = json.load(config)
|
||||
g.function1_str = config.get("f1")
|
||||
g.function2_str = config.get("f2")
|
||||
if g.function1_str is None or g.function2_str is None:
|
||||
raise samilaConfigError(CONFIG_FORMAT_ERROR)
|
||||
if 'matplotlib_version' in config:
|
||||
g.matplotlib_version = config['matplotlib_version']
|
||||
if 'python_version' in config:
|
||||
g.python_version = config['python_version']
|
||||
if '__version__' in config:
|
||||
g.__version__ = config['__version__']
|
||||
generate_config = config.get("generate")
|
||||
if generate_config is not None:
|
||||
g.seed = generate_config.get("seed")
|
||||
g.start = generate_config.get("start", DEFAULT_START)
|
||||
g.step = generate_config.get("step", DEFAULT_STEP)
|
||||
g.stop = generate_config.get("stop", DEFAULT_STOP)
|
||||
plot_config = data.get("plot")
|
||||
plot_config = config.get("plot")
|
||||
if plot_config is not None:
|
||||
g.color = plot_config.get("color", DEFAULT_COLOR)
|
||||
g.bgcolor = plot_config.get("bgcolor", DEFAULT_BACKGROUND_COLOR)
|
||||
g.cmap = _load_cmap(plot_config)
|
||||
g.spot_size = plot_config.get("spot_size", DEFAULT_SPOT_SIZE)
|
||||
g.projection = plot_config.get("projection", DEFAULT_PROJECTION)
|
||||
g.marker = plot_config.get("marker", DEFAULT_MARKER)
|
||||
g.alpha = plot_config.get("alpha", DEFAULT_ALPHA)
|
||||
g.linewidth = plot_config.get("linewidth", DEFAULT_LINEWIDTH)
|
||||
g.depth = plot_config.get("depth", DEFAULT_DEPTH)
|
||||
g.rotation = plot_config.get("rotation", DEFAULT_ROTATION)
|
||||
return
|
||||
raise samilaConfigError(CONFIG_TYPE_ERROR)
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Samila generative image."""
|
||||
import json
|
||||
import random
|
||||
import gc
|
||||
import itertools
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
from .functions import _GI_initializer, plot_params_filter, generate_params_filter
|
||||
from .functions import _GI_initializer, plot_params_filter, generate_params_filter, save_params_filter
|
||||
from .functions import get_config, get_data, get_python_version
|
||||
from .functions import float_range, save_data_file, save_fig_file, save_fig_buf, save_config_file
|
||||
from .functions import load_data, load_config, random_equation_gen, nft_storage_upload
|
||||
from .functions import set_background, rotate
|
||||
from .params import *
|
||||
from warnings import warn
|
||||
from warnings import warn, catch_warnings, simplefilter
|
||||
|
||||
|
||||
class GenerativeImage:
|
||||
|
@ -41,10 +44,14 @@ class GenerativeImage:
|
|||
load_config(self, config)
|
||||
elif data is not None:
|
||||
load_data(self, data)
|
||||
if self.matplotlib_version != matplotlib.__version__:
|
||||
if self.matplotlib_version != matplotlib.__version__ or \
|
||||
self.python_version != get_python_version() or \
|
||||
self.__version__ != SAMILA_VERSION:
|
||||
warn(
|
||||
MATPLOTLIB_VERSION_WARNING.format(
|
||||
self.matplotlib_version),
|
||||
VERSION_WARNING.format(
|
||||
self.matplotlib_version,
|
||||
self.python_version,
|
||||
self.__version__),
|
||||
RuntimeWarning)
|
||||
if self.function1 is None:
|
||||
if self.function1_str is None:
|
||||
|
@ -77,22 +84,33 @@ class GenerativeImage:
|
|||
generate_params_filter(self, seed, start, step, stop)
|
||||
self.data1 = []
|
||||
self.data2 = []
|
||||
self.missed_points_number = 0
|
||||
range1 = list(float_range(self.start, self.stop, self.step))
|
||||
range2 = list(float_range(self.start, self.stop, self.step))
|
||||
range_prod = list(itertools.product(range1, range2))
|
||||
for item in range_prod:
|
||||
range_prod = itertools.product(range1, range1)
|
||||
for point in range_prod:
|
||||
random.seed(self.seed)
|
||||
self.data1.append(self.function1(item[0], item[1]).real)
|
||||
self.data2.append(self.function2(item[0], item[1]).real)
|
||||
try:
|
||||
data1_ = self.function1(point[0], point[1]).real
|
||||
data2_ = self.function2(point[0], point[1]).real
|
||||
self.data1.append(data1_)
|
||||
self.data2.append(data2_)
|
||||
except Exception:
|
||||
self.missed_points_number += 1
|
||||
if len(self.data1) < (len(range1) ** 2):
|
||||
warn(CALCULATION_EXCEPTION_WARNING, RuntimeWarning)
|
||||
|
||||
def plot(
|
||||
self,
|
||||
color=None,
|
||||
bgcolor=None,
|
||||
cmap=None,
|
||||
spot_size=None,
|
||||
size=None,
|
||||
projection=None,
|
||||
alpha=None):
|
||||
marker=None,
|
||||
alpha=None,
|
||||
linewidth=None,
|
||||
rotation=None):
|
||||
"""
|
||||
Plot the generated art.
|
||||
|
||||
|
@ -100,58 +118,108 @@ class GenerativeImage:
|
|||
:type color: str
|
||||
:param bgcolor: background color
|
||||
:type bgcolor: str
|
||||
:param cmap: color map
|
||||
:type cmap: matplotlib.colors.Colormap or list of colors
|
||||
:param spot_size: point spot size
|
||||
:type spot_size: float
|
||||
:param size: figure size
|
||||
:type size: tuple
|
||||
:param projection: projection type
|
||||
:type projection: str
|
||||
:param marker: marker type
|
||||
:type marker: str
|
||||
:param alpha: point transparency
|
||||
:type alpha: float
|
||||
:param linewidth: width of line
|
||||
:type linewidth: float
|
||||
:param rotation: desired rotation (in degrees)
|
||||
:type rotation: float
|
||||
:return: None
|
||||
"""
|
||||
plot_params_filter(
|
||||
self,
|
||||
color,
|
||||
bgcolor,
|
||||
cmap,
|
||||
spot_size,
|
||||
size,
|
||||
projection,
|
||||
alpha)
|
||||
marker,
|
||||
alpha,
|
||||
linewidth,
|
||||
rotation)
|
||||
fig = plt.figure()
|
||||
fig.set_size_inches(self.size[0], self.size[1])
|
||||
fig.set_facecolor(self.bgcolor)
|
||||
ax = fig.add_subplot(111, projection=self.projection)
|
||||
ax.set_facecolor(self.bgcolor)
|
||||
ax.scatter(
|
||||
self.data2,
|
||||
self.data1,
|
||||
alpha=self.alpha,
|
||||
c=self.color,
|
||||
s=self.spot_size)
|
||||
set_background(self.bgcolor, fig, ax)
|
||||
with catch_warnings():
|
||||
simplefilter("ignore")
|
||||
ax.scatter(
|
||||
self.data2,
|
||||
self.data1,
|
||||
alpha=self.alpha,
|
||||
c=self.color,
|
||||
cmap=self.cmap,
|
||||
s=self.spot_size,
|
||||
lw=self.linewidth,
|
||||
marker=self.marker)
|
||||
ax.set_axis_off()
|
||||
ax.patch.set_zorder(-1)
|
||||
ax.add_artist(ax.patch)
|
||||
ax = rotate(fig, ax, self.rotation)
|
||||
self.fig = fig
|
||||
|
||||
def nft_storage(self, api_key, depth=DEFAULT_DEPTH):
|
||||
def nft_storage(
|
||||
self,
|
||||
api_key,
|
||||
upload_data=False,
|
||||
upload_config=False,
|
||||
depth=None,
|
||||
timeout=3000):
|
||||
"""
|
||||
Upload image to nft.storage.
|
||||
|
||||
:param api_key: API key
|
||||
:type api_key: str
|
||||
:param upload_data: upload data flag
|
||||
:type upload_data: bool
|
||||
:param upload_config: upload config flag
|
||||
:type upload_config: bool
|
||||
:param depth: image depth
|
||||
:type depth: float
|
||||
:param timeout: upload timeout (in seconds)
|
||||
:type timeout: int
|
||||
:return: result as dict
|
||||
"""
|
||||
response = save_fig_buf(self.fig, depth)
|
||||
save_params_filter(self, depth)
|
||||
response = save_fig_buf(self.fig, self.depth)
|
||||
if not response["status"]:
|
||||
return {"status": False, "message": response["message"]}
|
||||
buf = response["buffer"]
|
||||
response = nft_storage_upload(api_key=api_key, data=buf.getvalue())
|
||||
return response
|
||||
response = nft_storage_upload(
|
||||
api_key=api_key,
|
||||
data=buf.getvalue(),
|
||||
timeout=timeout)
|
||||
if upload_config == False and upload_data == False:
|
||||
return response
|
||||
result = {key: {'image': value} for key, value in response.items()}
|
||||
if upload_config:
|
||||
response = nft_storage_upload(
|
||||
api_key=api_key,
|
||||
data=json.dumps(get_config(self)),
|
||||
timeout=timeout)
|
||||
for key, value in response.items():
|
||||
result[key]['config'] = value
|
||||
if upload_data:
|
||||
response = nft_storage_upload(
|
||||
api_key=api_key,
|
||||
data=json.dumps(get_data(self)),
|
||||
timeout=timeout)
|
||||
for key, value in response.items():
|
||||
result[key]['data'] = value
|
||||
return result
|
||||
|
||||
def save_image(self, file_adr, depth=DEFAULT_DEPTH):
|
||||
def save_image(self, file_adr, depth=None):
|
||||
"""
|
||||
Save generated image.
|
||||
|
||||
|
@ -161,7 +229,8 @@ class GenerativeImage:
|
|||
:type depth: float
|
||||
:return: result as dict
|
||||
"""
|
||||
return save_fig_file(figure=self.fig, file_adr=file_adr, depth=depth)
|
||||
save_params_filter(self, depth)
|
||||
return save_fig_file(self.fig, file_adr, self.depth)
|
||||
|
||||
def save_data(self, file_adr='data.json'):
|
||||
"""
|
||||
|
@ -185,13 +254,16 @@ class GenerativeImage:
|
|||
|
||||
def __del__(self):
|
||||
"""
|
||||
Deconstructor.
|
||||
Destructor.
|
||||
|
||||
:return:None
|
||||
"""
|
||||
if self.fig is not None:
|
||||
self.fig.clf()
|
||||
plt.close(self.fig)
|
||||
del(self.data1)
|
||||
del(self.data2)
|
||||
gc.collect()
|
||||
try:
|
||||
del self.data1
|
||||
del self.data2
|
||||
if self.fig is not None:
|
||||
self.fig.clf()
|
||||
plt.close(self.fig)
|
||||
gc.collect()
|
||||
except Exception:
|
||||
gc.collect()
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
import math
|
||||
from enum import Enum
|
||||
from matplotlib import colors as mcolors
|
||||
from matplotlib import cm
|
||||
|
||||
SAMILA_VERSION = "0.5" # pragma: no cover
|
||||
SAMILA_VERSION = "1.1" # pragma: no cover
|
||||
|
||||
OVERVIEW = '''
|
||||
Samila is a generative art generator written in Python, Samila let's you
|
||||
|
@ -18,25 +19,39 @@ DEFAULT_STOP = math.pi
|
|||
DEFAULT_STEP = 0.01
|
||||
DEFAULT_COLOR = "black"
|
||||
DEFAULT_BACKGROUND_COLOR = "white"
|
||||
DEFAULT_CMAP = cm.get_cmap("viridis", 256)
|
||||
DEFAULT_CMAP_RANGE = 256
|
||||
DEFAULT_ALPHA = 0.1
|
||||
DEFAULT_LINEWIDTH = 1.5
|
||||
DEFAULT_IMAGE_SIZE = (10, 10)
|
||||
DEFAULT_SPOT_SIZE = 0.01
|
||||
DEFAULT_DEPTH = 1
|
||||
DEFAULT_ROTATION = 0.0
|
||||
DEFAULT_PROJECTION = "rectilinear"
|
||||
DEFAULT_MARKER = "."
|
||||
SEED_LOWER_BOUND = 0
|
||||
SEED_UPPER_BOUND = 2**20
|
||||
VALID_COLORS = list(dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS).keys())
|
||||
HEX_COLOR_PATTERN = r'^#(?:[0-9a-fA-F]{3}){1,2}$'
|
||||
NFT_STORAGE_API = "https://api.nft.storage/upload"
|
||||
NFT_STORAGE_LINK = "https://ipfs.io/ipfs/{}"
|
||||
NFT_STORAGE_SUCCESS_MESSAGE = "Everything seems good."
|
||||
FIG_SAVE_SUCCESS_MESSAGE = "Everything seems good."
|
||||
DATA_SAVE_SUCCESS_MESSAGE = "Everything seems good."
|
||||
NO_FIG_ERROR_MESSAGE = "No figure was found. First run `generate` and `plot` methods."
|
||||
DATA_TYPE_ERROR = "Provided data file is not supported. It should be either file or io.IOBase."
|
||||
DATA_FORMAT_ERROR = "Provided data file is not supported. It should include data1 and data2."
|
||||
CONFIG_TYPE_ERROR = "Provided config file is not supported. It should be either file or io.IOBase."
|
||||
CONFIG_FORMAT_ERROR = "Provided config file is not supported. It should include f1 and f2."
|
||||
CONFIG_NO_STR_FUNCTION_ERROR = "Config file can't be saved. At least one of the function1_str or function2_str is None."
|
||||
PLOT_DATA_ERROR = "Plotting process can't be Done because data{0} is empty. Use generate method first."
|
||||
COLOR_SIZE_ERROR = "Color list size is not equal to the data size."
|
||||
SAVE_NO_DATA_ERROR = "Data file can't be saved. At least one of the data1 or data2 is None."
|
||||
MATPLOTLIB_VERSION_WARNING = "Source matplotlib version({0}) is different from yours, plots may be different."
|
||||
INVALID_COLOR_TYPE_ERROR = "Given color/bgcolor type is not supported."
|
||||
VERSION_WARNING = "Your plots may differ as the version of matplotlib ({0}), Python ({1}), or Samila ({2}) that you are using is not the same as the source."
|
||||
CALCULATION_EXCEPTION_WARNING = "The given functions are undefined at some points. Your plot may not be complete."
|
||||
BOTH_COLOR_COMPLEMENT_WARNING = "It is not possible to set color and bgcolor to 'complement' at the same time! Both are automatically set to the previous or default selection."
|
||||
COLOR_NOT_FOUND_WARNING = "color '{0}' not found. Replacing it with '{1}'"
|
||||
|
||||
|
||||
class Projection(Enum):
|
||||
|
@ -53,14 +68,66 @@ class Projection(Enum):
|
|||
LAMBERT = "lambert"
|
||||
MOLLWEIDE = "mollweide"
|
||||
RECTILINEAR = "rectilinear"
|
||||
RANDOM = "random"
|
||||
|
||||
|
||||
class Marker(Enum):
|
||||
"""
|
||||
Samila Marker type class.
|
||||
|
||||
>>> marker = samila.Marker.POINT
|
||||
"""
|
||||
|
||||
DEFAULT = DEFAULT_MARKER
|
||||
POINT = "."
|
||||
PIXEL = ","
|
||||
CIRCLE = "o"
|
||||
TRIANGLE_DOWN = "v"
|
||||
TRIANGLE_UP = "^"
|
||||
TRIANGLE_LEFT = "<"
|
||||
TRIANGLE_RIGHT = ">"
|
||||
TRI_DOWN = "1"
|
||||
TRI_UP = "2"
|
||||
TRI_LEFT = "3"
|
||||
TRI_RIGHT = "4"
|
||||
OCTAGON = "8"
|
||||
SQUARE = "s"
|
||||
PENTAGON = "p"
|
||||
PLUS = "+"
|
||||
PLUS_FILLED = "P"
|
||||
STAR = "*"
|
||||
HEXAGON_VERTICAL = "h"
|
||||
HEXAGON_HORIZONTAL = "H"
|
||||
X = "x"
|
||||
X_FILLED = "X"
|
||||
DIAMOND = "D"
|
||||
DIAMON_THIN = "d"
|
||||
VLINE = "|"
|
||||
HLINE = "_"
|
||||
RANDOM = "random"
|
||||
|
||||
|
||||
RANDOM_COEF_LIST = [
|
||||
"random.uniform(-1,1)",
|
||||
"random.gauss(0,1)",
|
||||
"random.betavariate(1,1)",
|
||||
"random.gammavariate(1,1)",
|
||||
"random.lognormvariate(0,1)"]
|
||||
|
||||
ELEMENTS_LIST = [
|
||||
"{0}*math.exp({1})",
|
||||
"{0}*math.atan({1})",
|
||||
"{0}*math.asinh({1})",
|
||||
"{0}*math.acosh(abs({1})+1)",
|
||||
"{0}*math.erf({1})",
|
||||
"{0}*math.sqrt(abs({1}))",
|
||||
"{0}*math.log(abs({1})+1)",
|
||||
"{0}*math.tanh({1})",
|
||||
"{0}*math.cos({1})",
|
||||
"{0}*math.sin({1})",
|
||||
"{0}*math.tan({1})",
|
||||
"{0}*{1}",
|
||||
"{0}/{1}",
|
||||
"{0}*abs({1})",
|
||||
"{0}*math.ceil({1})",
|
||||
"{0}*math.floor({1})"]
|
||||
|
@ -69,16 +136,31 @@ ARGUMENTS_LIST = [
|
|||
"x*y",
|
||||
"x",
|
||||
"y",
|
||||
"1/x",
|
||||
"1/y",
|
||||
"x/y",
|
||||
"y-x",
|
||||
"x-y",
|
||||
"x+y",
|
||||
"x**3",
|
||||
"y**3",
|
||||
"x**2",
|
||||
"y**2",
|
||||
"(x**2)*y",
|
||||
"(y**2)*x",
|
||||
"(y**2)+(x**2)",
|
||||
"(y**2)-(x**2)",
|
||||
"(x**2)*(y**3)",
|
||||
"(x**3)*(y**2)",
|
||||
"x*(y**3)",
|
||||
"y*(x**3)"]
|
||||
|
||||
OPERATORS_LIST = ["+", "-"]
|
||||
OPERATORS_LIST = ["+", "-", "*", "/"]
|
||||
|
||||
RANDOM_EQUATION_MAX_COMPLEXITY = len(ELEMENTS_LIST) + 1
|
||||
|
||||
RANDOM_EQUATION_MIN_COMPLEXITY = 1
|
||||
|
||||
RANDOM_EQUATION_FOF_MAX_DEPTH = 3
|
||||
|
||||
RANDOM_EQUATION_FOF_MIN_DEPTH = 1
|
||||
|
|
16
setup.py
16
setup.py
|
@ -6,7 +6,8 @@ except ImportError:
|
|||
from distutils.core import setup
|
||||
|
||||
|
||||
MINIMAL_DESCRIPTION = '''Samila is a generative art generator written in Python, Samila let's you create arts based on many thousand points. The position of every single point is calculated by a formula, which has random parameters. Because of the random numbers, every image looks different.'''
|
||||
MINIMAL_DESCRIPTION = '''Samila is a generative art generator written in Python, Samila lets you create images based on many thousand points. The position of every single point is calculated by a
|
||||
formula, which has random parameters. Because of the random numbers, every image looks different.'''
|
||||
|
||||
|
||||
def get_requires():
|
||||
|
@ -32,14 +33,14 @@ def read_description():
|
|||
setup(
|
||||
name='samila',
|
||||
packages=['samila'],
|
||||
version='0.5',
|
||||
version='1.1',
|
||||
description='Generative ART',
|
||||
long_description=read_description(),
|
||||
long_description_content_type='text/markdown',
|
||||
author='Sepand Haghighi',
|
||||
author_email='info@4r7.ir',
|
||||
url='https://github.com/sepandhaghighi/samila',
|
||||
download_url='https://github.com/sepandhaghighi/samila/tarball/v0.5',
|
||||
author='Samila Development Team',
|
||||
author_email='info@samila.site',
|
||||
url='https://www.samila.site',
|
||||
download_url='https://github.com/sepandhaghighi/samila/tarball/v1.1',
|
||||
keywords="generative-art art nft file nft-storage",
|
||||
project_urls={
|
||||
'Source': 'https://github.com/sepandhaghighi/samila',
|
||||
|
@ -49,7 +50,7 @@ setup(
|
|||
install_requires=get_requires(),
|
||||
python_requires='>=3.5',
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Natural Language :: English',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
|
@ -67,6 +68,7 @@ setup(
|
|||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
],
|
||||
license='MIT',
|
||||
include_package_data=True
|
||||
|
|
|
@ -24,8 +24,9 @@ Traceback (most recent call last):
|
|||
...
|
||||
samila.errors.samilaPlotError: Plotting process can't be Done because data1 is empty. Use generate method first.
|
||||
>>> with open("data.json", 'w') as fp:
|
||||
... json.dump({'data1': [0]}, fp)
|
||||
... json.dump({'data1': [0], 'data2': [0]}, fp)
|
||||
>>> g = GenerativeImage(data=open('data.json', 'r'))
|
||||
>>> g.data2 = None
|
||||
>>> g.save_data()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
|
@ -34,10 +35,57 @@ samila.errors.samilaDataError: Data file can't be saved. At least one of the dat
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaPlotError: Plotting process can't be Done because data2 is empty. Use generate method first.
|
||||
>>> g.generate()
|
||||
>>> g.plot(color=(1, 2, 3, 4, 5))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaPlotError: Given color/bgcolor type is not supported.
|
||||
>>> g.plot(color=[0])
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaPlotError: Color list size is not the equal to the data size.
|
||||
>>> g = GenerativeImage(lambda x,y: x, lambda x,y: y)
|
||||
>>> result = g.save_config()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaConfigError: Config file can't be saved. At least one of the function1_str or function2_str is None.
|
||||
>>> from samila.functions import *
|
||||
>>> select_color(2)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaPlotError: Given color/bgcolor type is not supported.
|
||||
>>> filter_color(2,2)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaPlotError: Given color/bgcolor type is not supported.
|
||||
>>> g.plot(color=2, bgcolor=2)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaPlotError: Given color/bgcolor type is not supported.
|
||||
>>> with open("data.json", 'w') as fp:
|
||||
... json.dump({'data1': [0]}, fp)
|
||||
>>> g = GenerativeImage(data=open('data.json', 'r'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaDataError: Provided data file is not supported. It should include data1 and data2.
|
||||
>>> with open("data.json", 'w') as fp:
|
||||
... json.dump({'data2': [0]}, fp)
|
||||
>>> g = GenerativeImage(data=open('data.json', 'r'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaDataError: Provided data file is not supported. It should include data1 and data2.
|
||||
>>> with open("config.json", 'w') as fp:
|
||||
... json.dump({'f1': "x"}, fp)
|
||||
>>> g = GenerativeImage(config=open('config.json', 'r'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaConfigError: Provided config file is not supported. It should include f1 and f2.
|
||||
>>> with open("config.json", 'w') as fp:
|
||||
... json.dump({'f2': "x"}, fp)
|
||||
>>> g = GenerativeImage(config=open('config.json', 'r'))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
samila.errors.samilaConfigError: Provided config file is not supported. It should include f1 and f2.
|
||||
>>> os.remove('data.json')
|
||||
>>> os.remove('config.json')
|
||||
"""
|
||||
|
|
|
@ -1,6 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
>>> import random
|
||||
>>> import sys
|
||||
>>> from samila.functions import *
|
||||
>>> is_valid_color("blue")
|
||||
True
|
||||
>>> is_valid_color((0,0,0))
|
||||
True
|
||||
>>> is_valid_color((0.1,0.1,0,1))
|
||||
True
|
||||
>>> is_valid_color([1,1,1,1])
|
||||
True
|
||||
>>> is_valid_color("#FFFAAF")
|
||||
True
|
||||
>>> color_complement("#FFFFFF")
|
||||
'#000000'
|
||||
>>> color_complement("#FFAFBF")
|
||||
'#005040'
|
||||
>>> color_complement("#000000")
|
||||
'#ffffff'
|
||||
>>> select_color("blue")
|
||||
'blue'
|
||||
>>> select_color("#FFFFFA")
|
||||
'#fffffa'
|
||||
>>> select_color((0.1,0.1,0.1))
|
||||
(0.1, 0.1, 0.1)
|
||||
>>> select_color(None)
|
||||
>>> select_color("complement")
|
||||
'COMPLEMENT'
|
||||
>>> select_color("transparent")
|
||||
'TRANSPARENT'
|
||||
>>> s = list(float_range(1,1.5,0.1))
|
||||
>>> s
|
||||
[1.0, 1.1, 1.2000000000000002, 1.3000000000000003, 1.4000000000000004]
|
||||
|
@ -8,22 +37,62 @@
|
|||
True
|
||||
>>> is_same_data([1,1.1,1.2,1.3,1.4],[1,1.11,1.3,1.4,1.5])
|
||||
False
|
||||
>>> filter_color("yellow")
|
||||
'yellow'
|
||||
>>> filter_color((0.2,0.3,0.4))
|
||||
(0.2, 0.3, 0.4)
|
||||
>>> filter_color(2)
|
||||
>>> filter_color(4)
|
||||
>>> is_same_data(s,[1,1.1,1.2,1.3,1.4,1.5,1.6])
|
||||
False
|
||||
>>> is_same_data(s,[])
|
||||
False
|
||||
>>> filter_color("yellow", "blue")
|
||||
('yellow', 'blue')
|
||||
>>> filter_color((0.2,0.3,0.4), (0.2,0.3,0.4,1))
|
||||
((0.2, 0.3, 0.4), (0.2, 0.3, 0.4, 1))
|
||||
>>> filter_color("#FFFFFF", "#ffffe1")
|
||||
('#ffffff', '#ffffe1')
|
||||
>>> random.seed(2)
|
||||
>>> color1, bgcolor1 = filter_color("random", "random")
|
||||
>>> random.seed(3)
|
||||
>>> color2, bgcolor2 = filter_color("RANDOM", "RANDOM")
|
||||
>>> color1 == color2
|
||||
False
|
||||
>>> random.seed(2)
|
||||
>>> color1 = random_hex_color_gen()
|
||||
>>> random.seed(3)
|
||||
>>> color2 = random_hex_color_gen()
|
||||
>>> color1 == color2
|
||||
False
|
||||
>>> len(color1)
|
||||
7
|
||||
>>> len(color2)
|
||||
7
|
||||
>>> filter_size(2)
|
||||
>>> filter_size((2, 'test'))
|
||||
>>> filter_size((2, 3.5))
|
||||
(2, 3.5)
|
||||
>>> filter_projection(2)
|
||||
>>> filter_projection(Projection.POLAR)
|
||||
'polar'
|
||||
>>> random.seed(2)
|
||||
>>> projection1 = filter_projection(Projection.RANDOM)
|
||||
>>> random.seed(3)
|
||||
>>> projection2 = filter_projection(Projection.RANDOM)
|
||||
>>> projection1 == projection2
|
||||
False
|
||||
>>> filter_marker(3)
|
||||
>>> filter_marker(Marker.POINT)
|
||||
'.'
|
||||
>>> random.seed(2)
|
||||
>>> marker1 = filter_marker(Marker.RANDOM)
|
||||
>>> random.seed(3)
|
||||
>>> marker2 = filter_marker(Marker.RANDOM)
|
||||
>>> marker1 == marker2
|
||||
False
|
||||
>>> distance_calc("test","test1")
|
||||
1
|
||||
>>> distance_calc("te1st","test")
|
||||
1
|
||||
>>> distance_calc("test12","test234")
|
||||
3
|
||||
>>> get_python_version() == '.'.join(sys.version.split()[0].split('.')[:2])
|
||||
True
|
||||
>>> samila_help()
|
||||
<BLANKLINE>
|
||||
Samila is a generative art generator written in Python, Samila let's you
|
||||
|
@ -31,5 +100,6 @@ create arts based on many thousand points. The position of every single
|
|||
point is calculated by a formula, which has random parameters.
|
||||
Because of the random numbers, every image looks different.
|
||||
<BLANKLINE>
|
||||
Website : https://www.samila.site
|
||||
Repo : https://github.com/sepandhaghighi/samila
|
||||
"""
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
>>> import os
|
||||
>>> import math
|
||||
>>> import random
|
||||
>>> import time
|
||||
>>> from samila import GenerativeImage, Projection
|
||||
>>> from samila.params import VALID_COLORS
|
||||
|
@ -11,10 +9,7 @@
|
|||
>>> g.plot()
|
||||
>>> NFT_STORAGE_API_KEY = os.environ["NFT_STORAGE_API_KEY"]
|
||||
>>> g.generate()
|
||||
>>> random_projection = random.choice(list(Projection))
|
||||
>>> random_color = random.choice(VALID_COLORS)
|
||||
>>> random_bgcolor = random.choice(VALID_COLORS)
|
||||
>>> g.plot(projection=random_projection,color=random_color,bgcolor=random_bgcolor)
|
||||
>>> g.plot(projection=Projection.RANDOM, color="random", bgcolor="random")
|
||||
>>> counter = 0
|
||||
>>> try_limit = 10
|
||||
>>> status = False
|
||||
|
@ -25,4 +20,26 @@
|
|||
... time.sleep(10)
|
||||
>>> status
|
||||
True
|
||||
>>> status = False
|
||||
>>> counter = 0
|
||||
>>> while(status == False and counter<try_limit):
|
||||
... result = g.nft_storage(api_key=NFT_STORAGE_API_KEY, upload_config=True)
|
||||
... counter = counter + 1
|
||||
... status = all(result["status"].values())
|
||||
... time.sleep(10)
|
||||
>>> result['status']["image"]
|
||||
True
|
||||
>>> result['status']["config"]
|
||||
True
|
||||
>>> status = False
|
||||
>>> counter = 0
|
||||
>>> while(status == False and counter<try_limit):
|
||||
... result = g.nft_storage(api_key=NFT_STORAGE_API_KEY, upload_data=True)
|
||||
... counter = counter + 1
|
||||
... status = all(result["status"].values())
|
||||
... time.sleep(10)
|
||||
>>> result['status']["image"]
|
||||
True
|
||||
>>> result['status']["data"]
|
||||
True
|
||||
"""
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
>>> import pickle
|
||||
>>> import socket
|
||||
>>> import json
|
||||
>>> import sys
|
||||
>>> from matplotlib.colors import Colormap, ListedColormap
|
||||
>>> def guard(*args, **kwargs):
|
||||
... raise Exception("No internet connection!")
|
||||
>>> from samila import GenerativeImage, Projection
|
||||
>>> from samila import GenerativeImage, Projection, Marker
|
||||
>>> from samila.functions import is_same_data
|
||||
>>> import pickle
|
||||
>>> def f1(x,y):
|
||||
|
@ -22,12 +24,16 @@
|
|||
True
|
||||
>>> g.function2 == f2
|
||||
True
|
||||
>>> g.python_version == '.'.join(sys.version.split()[0].split('.')[:2])
|
||||
True
|
||||
>>> g.fig
|
||||
>>> g.generate()
|
||||
>>> isinstance(g.data1, list)
|
||||
True
|
||||
>>> isinstance(g.data2, list)
|
||||
True
|
||||
>>> g.missed_points_number == 0
|
||||
True
|
||||
>>> g.generate(seed=10, start=-2*math.pi, step=0.1, stop=math.pi/2)
|
||||
>>> g.seed
|
||||
10
|
||||
|
@ -43,20 +49,80 @@ True
|
|||
>>> result = g.save_image("test.png")
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> result["message"]
|
||||
'Everything seems good.'
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> g.plot(color='red')
|
||||
>>> g.plot(color='red', bgcolor='black')
|
||||
>>> result = g.save_image("test2.png", depth=5)
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> result["message"]
|
||||
'Everything seems good.'
|
||||
>>> from samila import GenerativeImage, Projection
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> g.plot(projection=Projection.POLAR, color='red', bgcolor='black')
|
||||
>>> g.color
|
||||
'red'
|
||||
>>> g.bgcolor
|
||||
'black'
|
||||
>>> g.plot(projection=Projection.POLAR, color='rod', bgcolor='blacc')
|
||||
>>> g.color
|
||||
'red'
|
||||
>>> g.bgcolor
|
||||
'black'
|
||||
>>> g.plot(projection=Projection.POLAR, color="#EEE245", bgcolor="#000000")
|
||||
>>> g.projection
|
||||
'polar'
|
||||
>>> g.color
|
||||
'#eee245'
|
||||
>>> g.bgcolor
|
||||
'#000000'
|
||||
>>> g.plot(projection=Projection.POLAR, color=(.1, .2, .8))
|
||||
>>> g.color
|
||||
(0.1, 0.2, 0.8)
|
||||
>>> g.plot(projection=Projection.POLAR, color="#FFFFF1", bgcolor="complement")
|
||||
>>> g.color
|
||||
'#fffff1'
|
||||
>>> g.bgcolor
|
||||
'#00000e'
|
||||
>>> g.plot(projection=Projection.POLAR, color="complement", bgcolor="#AAAAAA")
|
||||
>>> g.color
|
||||
'#555555'
|
||||
>>> g.bgcolor
|
||||
'#aaaaaa'
|
||||
>>> g.plot(projection=Projection.POLAR, color="complement", bgcolor="complement", marker=Marker.X, spot_size=100)
|
||||
>>> g.color
|
||||
'#555555'
|
||||
>>> g.bgcolor
|
||||
'#aaaaaa'
|
||||
>>> g.marker
|
||||
'x'
|
||||
>>> g.spot_size
|
||||
100
|
||||
>>> g.plot(rotation=45)
|
||||
>>> int(g.rotation)
|
||||
45
|
||||
>>> g.plot(bgcolor=(.1, .2, .8), spot_size=0.1)
|
||||
>>> g.plot(size=(20, 20))
|
||||
>>> g.size
|
||||
(20, 20)
|
||||
>>> g.plot(alpha=0.5, linewidth=2.2)
|
||||
>>> g.alpha
|
||||
0.5
|
||||
>>> g.linewidth
|
||||
2.2
|
||||
>>> random.seed(2)
|
||||
>>> g.plot(color="random", bgcolor="random", projection=Projection.RANDOM, marker=Marker.RANDOM)
|
||||
>>> color1, bgcolor1, projection1, marker1 = g.color, g.bgcolor, g.projection, g.marker
|
||||
>>> random.seed(3)
|
||||
>>> g.plot(color="random", bgcolor="random", projection=Projection.RANDOM, marker=Marker.RANDOM)
|
||||
>>> color2, bgcolor2, projection2, marker2 = g.color, g.bgcolor, g.projection, g.marker
|
||||
>>> color1 == color2
|
||||
False
|
||||
>>> bgcolor1 == bgcolor2
|
||||
False
|
||||
>>> projection1 == projection2
|
||||
False
|
||||
>>> marker1 == marker2
|
||||
False
|
||||
>>> result = g.nft_storage(api_key="")
|
||||
>>> result['status']
|
||||
False
|
||||
|
@ -82,7 +148,7 @@ False
|
|||
False
|
||||
>>> socket.socket = guard
|
||||
>>> g.generate()
|
||||
>>> g.plot(color=2,bgcolor=2)
|
||||
>>> g.plot()
|
||||
>>> result = g.nft_storage("")
|
||||
>>> result["status"]
|
||||
False
|
||||
|
@ -105,15 +171,24 @@ True
|
|||
>>> result = g.save_data()
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> g = GenerativeImage()
|
||||
>>> g.generate()
|
||||
>>> g.plot(color="white", bgcolor="black", spot_size=0.1)
|
||||
>>> g.plot(color="white", bgcolor="transparent")
|
||||
>>> g.bgcolor == "TRANSPARENT"
|
||||
True
|
||||
>>> g.plot()
|
||||
>>> result = g.save_config()
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> result = g.save_data()
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> g_ = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> g_.seed == g.seed
|
||||
True
|
||||
|
@ -127,6 +202,16 @@ True
|
|||
True
|
||||
>>> g.spot_size == g_.spot_size
|
||||
True
|
||||
>>> g.projection == g_.projection
|
||||
True
|
||||
>>> g.marker == g_.marker
|
||||
True
|
||||
>>> g.alpha == g_.alpha
|
||||
True
|
||||
>>> g.linewidth == g_.linewidth
|
||||
True
|
||||
>>> g.depth == g_.depth
|
||||
True
|
||||
>>> g_ = GenerativeImage(data=open("data.json", 'r'))
|
||||
>>> g.color == g_.color
|
||||
True
|
||||
|
@ -134,16 +219,71 @@ True
|
|||
True
|
||||
>>> g.spot_size == g_.spot_size
|
||||
True
|
||||
>>> with open("config.json", 'w') as fp:
|
||||
... json.dump({'f1': 'x'}, fp)
|
||||
>>> g = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> g.function1_str
|
||||
'x'
|
||||
>>> with open("config.json", 'w') as fp:
|
||||
... json.dump({'f2': 'x'}, fp)
|
||||
>>> g = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> g.function2_str
|
||||
'x'
|
||||
>>> g.projection == g_.projection
|
||||
True
|
||||
>>> g.marker == g_.marker
|
||||
True
|
||||
>>> g.rotation == g_.rotation
|
||||
True
|
||||
>>> g.alpha == g_.alpha
|
||||
True
|
||||
>>> g.linewidth == g_.linewidth
|
||||
True
|
||||
>>> g.depth == g_.depth
|
||||
True
|
||||
>>> g.plot(color="white", bgcolor="black", spot_size=2, projection=Projection.POLAR, marker=Marker.X, alpha=0.2, linewidth=1)
|
||||
>>> result = g.save_config()
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> result = g.save_data()
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> isinstance(result["message"], str)
|
||||
True
|
||||
>>> g_ = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> g_.seed == g.seed
|
||||
True
|
||||
>>> g_.function1_str == g.function1_str
|
||||
True
|
||||
>>> g_.function2_str == g.function2_str
|
||||
True
|
||||
>>> g.color == g_.color
|
||||
True
|
||||
>>> g.bgcolor == g_.bgcolor
|
||||
True
|
||||
>>> g.spot_size == g_.spot_size
|
||||
True
|
||||
>>> g.projection == g_.projection
|
||||
True
|
||||
>>> g.marker == g_.marker
|
||||
True
|
||||
>>> g.rotation == g_.rotation
|
||||
True
|
||||
>>> g.alpha == g_.alpha
|
||||
True
|
||||
>>> g.linewidth == g_.linewidth
|
||||
True
|
||||
>>> g.depth == g_.depth
|
||||
True
|
||||
>>> g_ = GenerativeImage(data=open("data.json", 'r'))
|
||||
>>> g.color == g_.color
|
||||
True
|
||||
>>> g.bgcolor == g_.bgcolor
|
||||
True
|
||||
>>> g.spot_size == g_.spot_size
|
||||
True
|
||||
>>> g.projection == g_.projection
|
||||
True
|
||||
>>> g.marker == g_.marker
|
||||
True
|
||||
>>> g.alpha == g_.alpha
|
||||
True
|
||||
>>> g.linewidth == g_.linewidth
|
||||
True
|
||||
>>> g.depth == g_.depth
|
||||
True
|
||||
>>> with open("config.json", 'w') as fp:
|
||||
... json.dump({'f1': 'y', 'f2': 'x'}, fp)
|
||||
>>> g = GenerativeImage(config=open("config.json", 'r'))
|
||||
|
@ -161,9 +301,66 @@ False
|
|||
[0]
|
||||
>>> g.data2
|
||||
[1]
|
||||
>>> with open("data.json", 'w') as fp:
|
||||
... json.dump({'data1': [0], 'data2': [1], 'plot':{}}, fp)
|
||||
>>> g = GenerativeImage(data=open("data.json", 'r'))
|
||||
>>> with open("config.json", 'w') as fp:
|
||||
... json.dump({'f1': "x", 'f2': "y", 'plot':{}}, fp)
|
||||
>>> g = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> g = GenerativeImage()
|
||||
>>> g.generate()
|
||||
>>> cm = Colormap(name="Purples")
|
||||
>>> g.plot(cmap=cm)
|
||||
>>> result = g.save_config("config.json")
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> g_ = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> (g_.cmap.colors == g.cmap.colors).all()
|
||||
True
|
||||
>>> cm = ["black", [0.6, 0.2, 0.2, 1], [0.5, 0.2, 0.2, 1], [0.4, 0.2, 0.2, 1], "yellow", [0.2, 0.2, 0.2, 1],]
|
||||
>>> g.plot(cmap=cm)
|
||||
>>> result = g.save_config("config.json")
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> g_ = GenerativeImage(config=open("config.json", 'r'))
|
||||
>>> g_.cmap.colors == g.cmap.colors
|
||||
True
|
||||
>>> g.plot(cmap="Purples")
|
||||
>>> cm = Colormap(name="viridis")
|
||||
>>> g.plot(cmap=cm)
|
||||
>>> cmap = [[0.7, 0.2, 0.2, 1], [0.6, 0.2, 0.2, 1], [0.3, 0.2, 0.2, 1], [0.2, 0.2, 0.2, 1]]
|
||||
>>> g.plot(cmap=ListedColormap(cmap))
|
||||
>>> g = GenerativeImage()
|
||||
>>> g.generate()
|
||||
>>> g.plot(cmap=cmap, color=g.data1)
|
||||
>>> result = g.save_data("data.json")
|
||||
>>> result["status"]
|
||||
True
|
||||
>>> g_ = GenerativeImage(data=open("data.json", "r"))
|
||||
>>> g_.plot()
|
||||
>>> g_.cmap.colors == g.cmap.colors
|
||||
True
|
||||
>>> g.plot(color=g.data1)
|
||||
>>> g_ = GenerativeImage()
|
||||
>>> del(g)
|
||||
>>> del g_.data1
|
||||
>>> del(g_)
|
||||
>>> g1 = GenerativeImage()
|
||||
>>> function1 = eval("lambda x, y:" + g1.function1_str)
|
||||
>>> function2 = eval("lambda x, y:" + g1.function2_str)
|
||||
>>> g2 = GenerativeImage(function1=function1, function2=function2)
|
||||
>>> g1.generate(seed=22)
|
||||
>>> g2.generate(seed=22)
|
||||
>>> is_same_data(g1.data1, g2.data1)
|
||||
True
|
||||
>>> is_same_data(g1.data2, g2.data2)
|
||||
True
|
||||
>>> len(g1.data1) > 0
|
||||
True
|
||||
>>> len(g1.data2) > 0
|
||||
True
|
||||
>>> del(g1)
|
||||
>>> del(g2)
|
||||
>>> os.remove("test.png")
|
||||
>>> os.remove("test2.png")
|
||||
>>> os.remove("data.json")
|
||||
|
|
|
@ -13,13 +13,38 @@ True
|
|||
>>> g_.data2 == g.data2
|
||||
True
|
||||
>>> with open('data.json', 'w') as fp:
|
||||
... json.dump({'data1': [0], 'data2': [0], '__version__': '0'}, fp)
|
||||
>>> with warns(RuntimeWarning, match=r"Your plots may differ as the version of matplotlib (.*), Python (.*), or Samila (.*) that you are using is not the same as the source."):
|
||||
... g = GenerativeImage(data=open('data.json', 'r'))
|
||||
>>> with open('config.json', 'w') as fp:
|
||||
... json.dump({'f1': 'x', 'f2': 'y', '__version__': '0'}, fp)
|
||||
>>> with warns(RuntimeWarning, match=r"Your plots may differ as the version of matplotlib (.*), Python (.*), or Samila (.*) that you are using is not the same as the source."):
|
||||
... g = GenerativeImage(config=open('config.json', 'r'))
|
||||
>>> with open('data.json', 'w') as fp:
|
||||
... json.dump({'data1': [0], 'data2': [0], 'python_version': '0'}, fp)
|
||||
>>> with warns(RuntimeWarning, match=r"Your plots may differ as the version of matplotlib (.*), Python (.*), or Samila (.*) that you are using is not the same as the source."):
|
||||
... g = GenerativeImage(data=open('data.json', 'r'))
|
||||
>>> with open('config.json', 'w') as fp:
|
||||
... json.dump({'f1': 'x', 'f2': 'y', 'python_version': '0'}, fp)
|
||||
>>> with warns(RuntimeWarning, match=r"Your plots may differ as the version of matplotlib (.*), Python (.*), or Samila (.*) that you are using is not the same as the source."):
|
||||
... g = GenerativeImage(config=open('config.json', 'r'))
|
||||
>>> with open('data.json', 'w') as fp:
|
||||
... json.dump({'data1': [0], 'data2': [0], 'matplotlib_version': '0'}, fp)
|
||||
>>> with warns(RuntimeWarning, match=r"Source matplotlib version(.*) is different from yours, plots may be different."):
|
||||
... g = GenerativeImage(lambda x,y: 0, lambda x,y: 0, data=open('data.json', 'r'))
|
||||
>>> with warns(RuntimeWarning, match=r"Your plots may differ as the version of matplotlib (.*), Python (.*), or Samila (.*) that you are using is not the same as the source."):
|
||||
... g = GenerativeImage(data=open('data.json', 'r'))
|
||||
>>> with open('config.json', 'w') as fp:
|
||||
... json.dump({'f1': 'x', 'f2': 'y', 'matplotlib_version': '0'}, fp)
|
||||
>>> with warns(RuntimeWarning, match=r"Source matplotlib version(.*) is different from yours, plots may be different."):
|
||||
>>> with warns(RuntimeWarning, match=r"Your plots may differ as the version of matplotlib (.*), Python (.*), or Samila (.*) that you are using is not the same as the source."):
|
||||
... g = GenerativeImage(config=open('config.json', 'r'))
|
||||
>>> g = GenerativeImage(lambda x, y: 1 / x, lambda x, y: 1 / (y - 1))
|
||||
>>> with warns(RuntimeWarning, match=r"The given functions are undefined at some points. Your plot may not be complete."):
|
||||
... g.generate(start=0, stop=2, step=0.1)
|
||||
>>> g.missed_points_number > 0
|
||||
True
|
||||
>>> with warns(RuntimeWarning, match=r"It is not possible to set color and bgcolor to 'complement' at the same time! Both are automatically set to the previous or default selection."):
|
||||
... g.plot(color='complement', bgcolor='complement')
|
||||
>>> with warns(RuntimeWarning, match=r"color 'rad' not found. Replacing it with 'red'"):
|
||||
... g.plot(color='rad')
|
||||
>>> os.remove('data.json')
|
||||
>>> os.remove('config.json')
|
||||
"""
|
||||
|
|
Ładowanie…
Reference in New Issue