kopia lustrzana https://github.com/sepandhaghighi/samila
509 wiersze
14 KiB
Python
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)
|