Rotation Added (#177)

* rotate : [INIT]

* edit : docstring edited.

* add : `rotate` function added.

* edit : docstring edited.

* add : `rotate` added to config and data files.

* log : changes logged.

* update : document updated.

* test : tests added (#176)

* add : `PIL` added to dependecies.

* fix : typo fixed in `requirements.txt`.

* remove : extra import in `genimage.py` removed.

* add : version for Pillow.

---------

Co-authored-by: sepandhaghighi <sepand.haghighi@yahoo.com>
pull/180/head
Sadra Sabouri 2023-03-26 18:30:40 +03:30 zatwierdzone przez GitHub
rodzic e3c9cede8c
commit a54a5107a5
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
8 zmienionych plików z 93 dodań i 9 usunięć

Wyświetl plik

@ -10,7 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- `RANDOM_EQUATION_MIN_COMPLEXITY` parameter - `RANDOM_EQUATION_MIN_COMPLEXITY` parameter
- `RANDOM_EQUATION_FOF_MAX_DEPTH` parameter - `RANDOM_EQUATION_FOF_MAX_DEPTH` parameter
- `RANDOM_EQUATION_FOF_MIN_DEPTH` parameter - `RANDOM_EQUATION_FOF_MIN_DEPTH` parameter
- `rotate` function
### Changed ### Changed
- `rotation` parameter added to `plot` method
- `load_config` function modified - `load_config` function modified
- Random mode modified - Random mode modified
- `RANDOM_EQUATION_GEN_COMPLEXITY` parameter renamed to `RANDOM_EQUATION_MAX_COMPLEXITY` - `RANDOM_EQUATION_GEN_COMPLEXITY` parameter renamed to `RANDOM_EQUATION_MAX_COMPLEXITY`

Wyświetl plik

@ -170,6 +170,17 @@ Samila is a generative art generator written in Python, Samila lets you create i
* 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` * 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` * 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 ### Range
```pycon ```pycon
>>> g = GenerativeImage(f1, f2) >>> g = GenerativeImage(f1, f2)

Wyświetl plik

@ -133,6 +133,28 @@
" plt.close()" " plt.close()"
] ]
}, },
{
"attachments": {},
"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", "cell_type": "markdown",
"metadata": {}, "metadata": {},

Wyświetl plik

@ -1,3 +1,4 @@
matplotlib>=3.0.0 matplotlib>=3.0.0
requests>=2.20.0 requests>=2.20.0
art>=1.8 art>=1.8
Pillow>=6.2

Wyświetl plik

@ -11,8 +11,9 @@ import random
import matplotlib import matplotlib
from matplotlib import cm from matplotlib import cm
from matplotlib.colors import ListedColormap from matplotlib.colors import ListedColormap
from PIL import Image
from .params import DEFAULT_MARKER, DEFAULT_START, DEFAULT_STOP, DEFAULT_STEP, DEFAULT_COLOR, DEFAULT_IMAGE_SIZE, DEFAULT_DEPTH 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 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 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 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 DATA_TYPE_ERROR, DATA_FORMAT_ERROR, CONFIG_TYPE_ERROR, CONFIG_FORMAT_ERROR, PLOT_DATA_ERROR, CONFIG_NO_STR_FUNCTION_ERROR
@ -307,6 +308,30 @@ def filter_size(size):
return None 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( def plot_params_filter(
g, g,
color=None, color=None,
@ -317,7 +342,8 @@ def plot_params_filter(
projection=None, projection=None,
marker=None, marker=None,
alpha=None, alpha=None,
linewidth=None): linewidth=None,
rotation=None):
""" """
Filter plot method parameters. Filter plot method parameters.
@ -341,6 +367,8 @@ def plot_params_filter(
:type alpha: float :type alpha: float
:param linewidth: width of line :param linewidth: width of line
:type linewidth: float :type linewidth: float
:param rotation: desired rotation (in degrees)
:type rotation: float
:return: None :return: None
""" """
if g.data1 is None: if g.data1 is None:
@ -378,8 +406,10 @@ def plot_params_filter(
alpha = g.alpha alpha = g.alpha
if linewidth is None: if linewidth is None:
linewidth = g.linewidth linewidth = g.linewidth
g.color, g.bgcolor, g.cmap, g.spot_size, g.size, g.projection, g.marker, g.alpha, g.linewidth = \ if rotation is None:
color, bgcolor, cmap, spot_size, size, projection, marker, alpha, linewidth 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( def generate_params_filter(
@ -464,6 +494,7 @@ def _GI_initializer(g, function1, function2):
g.marker = DEFAULT_MARKER g.marker = DEFAULT_MARKER
g.alpha = DEFAULT_ALPHA g.alpha = DEFAULT_ALPHA
g.linewidth = DEFAULT_LINEWIDTH g.linewidth = DEFAULT_LINEWIDTH
g.rotation = DEFAULT_ROTATION
g.depth = DEFAULT_DEPTH g.depth = DEFAULT_DEPTH
g.missed_points_number = 0 g.missed_points_number = 0
@ -558,7 +589,8 @@ def get_data(g):
"marker": g.marker, "marker": g.marker,
"alpha": g.alpha, "alpha": g.alpha,
"linewidth": g.linewidth, "linewidth": g.linewidth,
"depth": g.depth "depth": g.depth,
"rotation": g.rotation,
} }
data['matplotlib_version'] = matplotlib_version data['matplotlib_version'] = matplotlib_version
data['python_version'] = python_version data['python_version'] = python_version
@ -595,7 +627,8 @@ def get_config(g):
"marker": g.marker, "marker": g.marker,
"alpha": g.alpha, "alpha": g.alpha,
"linewidth": g.linewidth, "linewidth": g.linewidth,
"depth": g.depth "depth": g.depth,
"rotation": g.rotation,
} }
config['matplotlib_version'] = matplotlib_version config['matplotlib_version'] = matplotlib_version
config['python_version'] = python_version config['python_version'] = python_version
@ -783,6 +816,7 @@ def load_data(g, data):
g.alpha = plot_config.get("alpha", DEFAULT_ALPHA) g.alpha = plot_config.get("alpha", DEFAULT_ALPHA)
g.linewidth = plot_config.get("linewidth", DEFAULT_LINEWIDTH) g.linewidth = plot_config.get("linewidth", DEFAULT_LINEWIDTH)
g.depth = plot_config.get("depth", DEFAULT_DEPTH) g.depth = plot_config.get("depth", DEFAULT_DEPTH)
g.rotation = plot_config.get("rotation", DEFAULT_ROTATION)
return return
raise samilaDataError(DATA_TYPE_ERROR) raise samilaDataError(DATA_TYPE_ERROR)
@ -824,5 +858,6 @@ def load_config(g, config):
g.alpha = plot_config.get("alpha", DEFAULT_ALPHA) g.alpha = plot_config.get("alpha", DEFAULT_ALPHA)
g.linewidth = plot_config.get("linewidth", DEFAULT_LINEWIDTH) g.linewidth = plot_config.get("linewidth", DEFAULT_LINEWIDTH)
g.depth = plot_config.get("depth", DEFAULT_DEPTH) g.depth = plot_config.get("depth", DEFAULT_DEPTH)
g.rotation = plot_config.get("rotation", DEFAULT_ROTATION)
return return
raise samilaConfigError(CONFIG_TYPE_ERROR) raise samilaConfigError(CONFIG_TYPE_ERROR)

Wyświetl plik

@ -10,7 +10,7 @@ from .functions import _GI_initializer, plot_params_filter, generate_params_filt
from .functions import get_config, get_data, get_python_version 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 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 load_data, load_config, random_equation_gen, nft_storage_upload
from .functions import set_background from .functions import set_background, rotate
from .params import * from .params import *
from warnings import warn, catch_warnings, simplefilter from warnings import warn, catch_warnings, simplefilter
@ -107,7 +107,8 @@ class GenerativeImage:
projection=None, projection=None,
marker=None, marker=None,
alpha=None, alpha=None,
linewidth=None): linewidth=None,
rotation=None):
""" """
Plot the generated art. Plot the generated art.
@ -129,6 +130,8 @@ class GenerativeImage:
:type alpha: float :type alpha: float
:param linewidth: width of line :param linewidth: width of line
:type linewidth: float :type linewidth: float
:param rotation: desired rotation (in degrees)
:type rotation: float
:return: None :return: None
""" """
plot_params_filter( plot_params_filter(
@ -141,7 +144,8 @@ class GenerativeImage:
projection, projection,
marker, marker,
alpha, alpha,
linewidth) linewidth,
rotation)
fig = plt.figure() fig = plt.figure()
fig.set_size_inches(self.size[0], self.size[1]) fig.set_size_inches(self.size[0], self.size[1])
ax = fig.add_subplot(111, projection=self.projection) ax = fig.add_subplot(111, projection=self.projection)
@ -160,6 +164,7 @@ class GenerativeImage:
ax.set_axis_off() ax.set_axis_off()
ax.patch.set_zorder(-1) ax.patch.set_zorder(-1)
ax.add_artist(ax.patch) ax.add_artist(ax.patch)
ax = rotate(fig, ax, self.rotation)
self.fig = fig self.fig = fig
def nft_storage( def nft_storage(

Wyświetl plik

@ -26,6 +26,7 @@ DEFAULT_LINEWIDTH = 1.5
DEFAULT_IMAGE_SIZE = (10, 10) DEFAULT_IMAGE_SIZE = (10, 10)
DEFAULT_SPOT_SIZE = 0.01 DEFAULT_SPOT_SIZE = 0.01
DEFAULT_DEPTH = 1 DEFAULT_DEPTH = 1
DEFAULT_ROTATION = 0.0
DEFAULT_PROJECTION = "rectilinear" DEFAULT_PROJECTION = "rectilinear"
DEFAULT_MARKER = "." DEFAULT_MARKER = "."
SEED_LOWER_BOUND = 0 SEED_LOWER_BOUND = 0

Wyświetl plik

@ -97,6 +97,9 @@ True
'x' 'x'
>>> g.spot_size >>> g.spot_size
100 100
>>> g.plot(rotation=45)
>>> int(g.rotation)
45
>>> g.plot(bgcolor=(.1, .2, .8), spot_size=0.1) >>> g.plot(bgcolor=(.1, .2, .8), spot_size=0.1)
>>> g.plot(size=(20, 20)) >>> g.plot(size=(20, 20))
>>> g.size >>> g.size
@ -220,6 +223,8 @@ True
True True
>>> g.marker == g_.marker >>> g.marker == g_.marker
True True
>>> g.rotation == g_.rotation
True
>>> g.alpha == g_.alpha >>> g.alpha == g_.alpha
True True
>>> g.linewidth == g_.linewidth >>> g.linewidth == g_.linewidth
@ -254,6 +259,8 @@ True
True True
>>> g.marker == g_.marker >>> g.marker == g_.marker
True True
>>> g.rotation == g_.rotation
True
>>> g.alpha == g_.alpha >>> g.alpha == g_.alpha
True True
>>> g.linewidth == g_.linewidth >>> g.linewidth == g_.linewidth