samila/samila/functions.py

509 wiersze
14 KiB
Python

# -*- coding: utf-8 -*-
"""Samila functions."""
import requests
import io
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 .params import NO_FIG_ERROR_MESSAGE, FIG_SAVE_SUCCESS_MESSAGE, NFT_STORAGE_SUCCESS_MESSAGE, SAVE_NO_DATA_ERROR
from .params import DATA_SAVE_SUCCESS_MESSAGE, SEED_LOWER_BOUND, SEED_UPPER_BOUND
from .params import ELEMENTS_LIST, ARGUMENTS_LIST, OPERATORS_LIST
from .errors import samilaDataError, samilaPlotError, samilaConfigError
def random_equation_gen():
"""
Generate random equation.
:return: equation as str
"""
num_elements = random.randint(2, len(ELEMENTS_LIST) + 3)
result = ""
index = 1
random_coef = "random.uniform(-1,1)"
while(index <= num_elements):
argument = random.choice(ARGUMENTS_LIST)
result = result + \
random.choice(ELEMENTS_LIST).format(random_coef, argument)
if index < num_elements:
result = result + random.choice(OPERATORS_LIST)
index = index + 1
return result
def float_range(start, stop, step):
"""
Generate float range.
:param start: start point
:type start: float
:param stop: stop point
:type step: float
:param step: step
:type step: float
:return: yield result
"""
while start < stop:
yield float(start)
start += step
def distance_calc(s1, s2):
"""
Calculate Levenshtein distance between two words.
:param s1: first string
:type s1 : str
:param s2: second string
:type s2 : str
:return: distance between two string
References :
1- https://stackoverflow.com/questions/2460177/edit-distance-in-python
2- https://en.wikipedia.org/wiki/Levenshtein_distance
"""
if len(s1) > len(s2):
s1, s2 = s2, s1
distances = range(len(s1) + 1)
for i2, c2 in enumerate(s2):
distances_ = [i2 + 1]
for i1, c1 in enumerate(s1):
if c1 == c2:
distances_.append(distances[i1])
else:
distances_.append(
1 + min((distances[i1], distances[i1 + 1], distances_[-1])))
distances = distances_
return distances[-1]
def filter_color(color):
"""
Filter given color and return it.
:param color: given color
:type color: str or tuple
:return: filtered version of color
"""
if isinstance(color, tuple):
return color
if isinstance(color, str):
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
def filter_projection(projection):
"""
Filter given projection.
:param projection: given projection
:type projection: Projection enum
:return: filtered version of projection
"""
if isinstance(projection, Projection):
return projection.value
return None
def filter_float(value):
"""
Filter given float value.
:param value: given value
:type value: float
:return: filtered version of value
"""
if isinstance(value, (float, int)):
return value
return None
def filter_size(size):
"""
Filter given image size.
:param value: given size
:type value: tuple of float
:return: filtered version of size
"""
if isinstance(size, tuple):
if not any(map(lambda x: x != filter_float(x), size)):
return size
return None
def plot_params_filter(
g,
color=None,
bgcolor=None,
spot_size=None,
size=None,
projection=None,
alpha=None):
"""
Filter plot method parameters.
:param g: generative image instance
:type g: GenerativeImage
:param color: point colors
:type color: str
:param bgcolor: background color
:type bgcolor: str
: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 alpha: point transparency
:type alpha: 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])
projection = filter_projection(projection)
alpha = filter_float(alpha)
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 spot_size is None:
spot_size = g.spot_size
if size is None:
size = g.size
if projection is None:
projection = g.projection
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
def generate_params_filter(
g,
seed=None,
start=None,
step=None,
stop=None):
"""
Filter generate method parameters.
:param g: generative image instance
:type g: GenerativeImage
:param seed: random seed
:type seed: int
:param start: range start point
:type start: float
:param step: range step size
:type step: float
:param stop: range stop point
:type stop: float
:return: None
"""
start, step, stop = map(filter_float, [start, step, stop])
if start is None:
start = g.start
if step is None:
step = g.step
if stop is None:
stop = g.stop
if seed is None:
seed = g.seed
if g.seed is None:
seed = random.randint(SEED_LOWER_BOUND, SEED_UPPER_BOUND)
g.seed, g.start, g.step, g.stop = seed, start, step, stop
def _GI_initializer(g, function1, function2):
"""
Initialize the generative image.
:param g: generative image instance
:type g: GenerativeImage
:param function1: function 1
:type function1: python or lambda function
:param function2: function 2
:type function2: python or lambda function
:return: None
"""
g.matplotlib_version = matplotlib.__version__
g.function1 = function1
g.function1_str = None
g.function2 = function2
g.function2_str = None
g.fig = None
g.seed = None
g.start = DEFAULT_START
g.step = DEFAULT_STEP
g.stop = DEFAULT_STOP
g.data1 = None
g.data2 = None
g.color = DEFAULT_COLOR
g.bgcolor = DEFAULT_BACKGROUND_COLOR
g.spot_size = DEFAULT_SPOT_SIZE
g.size = DEFAULT_IMAGE_SIZE
g.projection = DEFAULT_PROJECTION
g.alpha = DEFAULT_ALPHA
def nft_storage_upload(api_key, data):
"""
Upload file to nft.storage.
:param api_key: API key
:type api_key: str
:param data: image data
:type data: binary
:return: result as dict
"""
result = {"status": True, "message": NFT_STORAGE_SUCCESS_MESSAGE}
try:
headers = {'Authorization': 'Bearer {0}'.format(api_key)}
response = requests.post(
url=NFT_STORAGE_API,
data=data,
headers=headers)
response_json = response.json()
if response_json["ok"]:
return result
result["status"] = False
result["message"] = response_json["error"]["message"]
return result
except Exception as e:
result["status"] = False
result["message"] = str(e)
return result
def save_data_file(g, file_adr):
"""
Save data as file.
:param g: generative image instance
:type g: GenerativeImage
:param file_adr: file address
:type file_adr: str
:return: result as dict
"""
matplotlib_version = matplotlib.__version__
data = {}
if g.data1 is None or g.data2 is None:
raise samilaDataError(SAVE_NO_DATA_ERROR)
data['data1'] = g.data1
data['data2'] = g.data2
data['plot'] = {
"color": g.color,
"bgcolor": g.bgcolor,
"spot_size": g.spot_size,
"projection": g.projection,
"alpha": g.alpha
}
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
def save_config_file(g, file_adr):
"""
Save config as file.
:param g: generative image instance
:type g: GenerativeImage
:param file_adr: file address
: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
result = {"status": True, "message": DATA_SAVE_SUCCESS_MESSAGE}
try:
with open(file_adr, 'w') as fp:
json.dump(data, fp, indent=4)
except Exception as e:
result["status"] = False
result["message"] = str(e)
return result
def save_fig_file(figure, file_adr, depth):
"""
Save figure as file.
:param figure: matplotlib figure
:type figure: matplotlib.figure.Figure
:param file_adr: file address
:type file_adr: str
:param depth: image depth
:type depth: float
:return: result as dict
"""
if figure is None:
return {"status": False, "message": NO_FIG_ERROR_MESSAGE}
result = {"status": True, "message": FIG_SAVE_SUCCESS_MESSAGE}
try:
figure.savefig(
file_adr,
dpi=depth * figure.dpi,
facecolor=figure.get_facecolor(),
edgecolor='none')
return result
except Exception as e:
result["status"] = False
result["message"] = str(e)
return result
def save_fig_buf(figure, depth):
"""
Save figure as buffer.
:param figure: matplotlib figure
:type figure: matplotlib.figure.Figure
:param depth: image depth
:type depth: float
:return: result as dict
"""
if figure is None:
return {"status": False, "message": NO_FIG_ERROR_MESSAGE}
result = {
"status": True,
"message": FIG_SAVE_SUCCESS_MESSAGE,
"buffer": None}
try:
buf = io.BytesIO()
figure.savefig(
buf,
dpi=depth * figure.dpi,
format='png',
facecolor=figure.get_facecolor(),
edgecolor='none')
result["buffer"] = buf
return result
except Exception as e:
result["status"] = False
result["message"] = str(e)
return result
def samila_help():
"""
Print samila details.
:return: None
"""
print(OVERVIEW)
print("Repo : https://github.com/sepandhaghighi/samila")
def is_same_data(data1, data2, precision=10**-5):
"""
Compare two data to be the same.
:param data1: given data1
:type data1: list
:param data2: given data2
:type data2: list
:param precision: comparing precision
:type precision: float
:return: True if they are the same
"""
is_same = map(lambda x, y: abs(x - y) < precision, data1, data2)
return all(is_same)
def load_data(g, data):
"""
Load data file.
:param g: generative image instance
:type g: GenerativeImage
:param data: prior generated data
:type data: (io.IOBase & file)
:return: None
"""
if isinstance(data, io.IOBase):
data = json.load(data)
g.data1 = data.get('data1')
g.data2 = data.get('data2')
if 'matplotlib_version' in data:
g.matplotlib_version = data['matplotlib_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.spot_size = plot_config.get("spot_size", DEFAULT_SPOT_SIZE)
g.projection = plot_config.get("projection", DEFAULT_PROJECTION)
g.alpha = plot_config.get("alpha", DEFAULT_ALPHA)
return
raise samilaDataError(DATA_TYPE_ERROR)
def load_config(g, config):
"""
Load config file.
:param g: generative image instance
:type g: GenerativeImage
:param config: config JSON file
:type config: (io.IOBase & file)
: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")
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")
if plot_config is not None:
g.color = plot_config.get("color", DEFAULT_COLOR)
g.bgcolor = plot_config.get("bgcolor", DEFAULT_BACKGROUND_COLOR)
g.spot_size = plot_config.get("spot_size", DEFAULT_SPOT_SIZE)
g.projection = plot_config.get("projection", DEFAULT_PROJECTION)
g.alpha = plot_config.get("alpha", DEFAULT_ALPHA)
return
raise samilaConfigError(CONFIG_TYPE_ERROR)