Skip to content

Commit

Permalink
Merge pull request #16 from fsepy/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
fuyans authored May 21, 2020
2 parents f0f3409 + 4ea4890 commit 5083e5b
Show file tree
Hide file tree
Showing 21 changed files with 981 additions and 101 deletions.
14 changes: 7 additions & 7 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
numpy>=1.17
pandas>=0.25
scipy>=1.3
seaborn>=0.9
numpy>=1.17.1
pandas>=0.25.1
scipy>=1.3.1
matplotlib>=3.1.1
tqdm>=4.36
xlrd>=1.2
plotly>=4.2
xlrd>=1.2.0
plotly>=4.2.1
docopt>=0.6
pyside2>=5.12
openpyxl>=3.0.3
openpyxl>=3.0.3
8 changes: 5 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@
"sfeprapy.mcs1",
"sfeprapy.func",
"sfeprapy.dist_fit",
"sfeprapy.guilayout",
"sfeprapy.guilogic",
"sfeprapy.cli",
"sfeprapy.gui",
"sfeprapy.gui.layout",
"sfeprapy.gui.logic",
],
install_requires=requirements,
include_package_data=True,
entry_points={"console_scripts": ["sfeprapy=sfeprapy.cli:main"]},
entry_points={"console_scripts": ["sfeprapy=sfeprapy.cli.__main__:main"]},
)
2 changes: 1 addition & 1 deletion sfeprapy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"""

__version__ = "0.7.2"
__version__ = "0.7.1.post6"


def check_pip_upgrade():
Expand Down
Empty file added sfeprapy/cli/__init__.py
Empty file.
20 changes: 11 additions & 9 deletions sfeprapy/cli.py → sfeprapy/cli/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""SfePrapy CLI Help.
Usage:
sfeprapy
sfeprapy mcs0 gui
sfeprapy mcs0 run [-p=<int>] <file_name>
sfeprapy mcs0 figure <file_name>
Expand All @@ -18,14 +19,21 @@
-h --help to show this message.
Commands:
mcs0 gui A GUI version of sfeprapy.
Will run `mcs0 gui` if no command is supplied.
mcs0 gui Experimental GUI version of sfeprapy.
mcs0 run Monte Carlo Simulation to solve equivalent time exposure in ISO 834 fire, method 0.
mcs0 figure produce figure from the output file <file_name>.
mcs0 template save example input file to <file_name>.
"""

from docopt import docopt

from sfeprapy.func.stats_dist_fit import auto_fit_2
from sfeprapy.gui.__main__ import main as main_gui
from sfeprapy.mcs0 import EXAMPLE_INPUT_CSV
from sfeprapy.mcs0.__main__ import main as mcs0
from sfeprapy.mcs0.__main__ import save_figure as mcs0_figure


def main():
import os
Expand All @@ -38,12 +46,10 @@ def main():
if arguments["mcs0"]:

if arguments["gui"]:
from sfeprapy.guilogic.main import main as main_
main_()
main_gui()
return 0

elif arguments["figure"]:
from sfeprapy.mcs0.__main__ import save_figure as mcs0_figure

mcs0_figure(fp_mcs0_out=arguments["<file_name>"])

Expand All @@ -57,17 +63,13 @@ def main():
f.write(EXAMPLE_INPUT_CSV)

else:
from sfeprapy.mcs0.__main__ import main as mcs0

fp_mcs_in = arguments["<file_name>"]
n_threads = arguments["-p"] or 2
mcs0(fp_mcs_in=fp_mcs_in, n_threads=int(n_threads))

elif arguments["distfit"]:

# Prerequisites
from sfeprapy.func.stats_dist_fit import auto_fit_2

# Default values
data_type = arguments["--data_t"] or 2
distribution_list = arguments["--dist_g"] or 1
Expand All @@ -80,4 +82,4 @@ def main():
)

else:
print("instruction unclear.")
main_gui()
273 changes: 273 additions & 0 deletions sfeprapy/func/asciiplot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
# -*- coding: utf-8 -*-

from typing import Union, Tuple

import numpy as np


class AsciiPlot:

def __init__(self, size: Tuple[float, float] = (80, 35)):
self.__size = None
self.__xlim = None
self.__ylim = None
self.__plot_canvas = None
self.__plot_yaxis = None
self.__plot_xaxis = None
self.__plot = None

self.size = size

def plot(self, x, y, xlim: tuple = None, ylim: tuple = None):

if xlim is None:
xlim = [min(x), max(x)]
if ylim is None:
ylim = [min(y), max(y)]
if ylim[0] == ylim[1] == 0:
ylim = -1., 1.
elif ylim[0] == ylim[1]:
ylim[0] -= ylim[0] * 0.1
ylim[1] += ylim[1] * 0.11

yaxis_size = (None, self.size[1] - 2)
self.__plot_yaxis = self.__make_yaxis(ylim, yaxis_size)
xaxis_size = (self.size[0] - self.__plot_yaxis.shape[1], None)
self.__plot_xaxis = self.__make_xaxis(xlim, xaxis_size)
canvas_size = (self.size[0] - self.__plot_yaxis.shape[1], self.size[1] - self.__plot_xaxis.shape[0])
self.__plot_canvas = self._make_canvas(x, y, xlim, ylim, canvas_size)
self.__plot = self.__assemble(self.__plot_canvas, self.__plot_xaxis, self.__plot_yaxis)

return self

def str(self):
return self.__list2str(self.__plot)

def show(self):
try:
assert self.__plot is not None
except AssertionError:
ValueError('No plot to show')

print(self.__list2str(self.__plot))

def save(self, fp: str):
try:
assert self.__plot is not None
except AssertionError:
ValueError('No plot to save')

with open(fp, 'w+') as f:
f.write(self.__list2str(self.__plot))

@staticmethod
def __list2str(v: Union[list, np.ndarray]) -> str:
return '\n'.join([''.join([str(j) for j in i]) for i in v])

@staticmethod
def _make_canvas(
x: Union[list, np.ndarray],
y: Union[list, np.ndarray],
xlim: tuple = None,
ylim: tuple = None,
size: tuple = (80, 40),
mat_plot_canvas: np.ndarray = None
) -> np.ndarray:
# correct data type if necessary
if not isinstance(x, np.ndarray):
x = np.array(x)
if not isinstance(y, np.ndarray):
y = np.array(y)
if mat_plot_canvas is not None:
assert mat_plot_canvas.shape[0] == size[::-1][0]
assert mat_plot_canvas.shape[1] == size[::-1][1]
else:
mat_plot_canvas = np.zeros(shape=size[::-1]) # canvas matrix containing the plot

# workout data plot boundaries
if xlim:
x1, x2 = xlim
else:
x1, x2 = min(x), max(x)
if ylim:
y1, y2 = ylim
else:
y1, y2 = min(y), max(y)

# workout translator arrays
# example
# mat_plot_canvas[i, j] equates location ii[i], jj[i] in data coordination system
ii = np.linspace(y1, y2, size[1])
jj = np.linspace(x1, x2, size[0])
dx, dy = jj[1] - jj[0], ii[1] - ii[0]

# interpolate x and y, i.e. to increase resolution of the provided x, y
xi = np.arange(min(x), max(x) + dx / 2, dx / 2)
yi = np.interp(xi, x, y)

# plot, assign value 1 to cells in `mat_plot_canvas` the x, y line lands
for i in range(len(xi)):
x_, y_ = xi[i], yi[i]

# cells that the line lands
jjp = np.argwhere(np.logical_and(jj > x_ - 0.5 * dx, jj < x_ + 0.5 * dx))
iip = np.argwhere(np.logical_and(ii > y_ - 0.5 * dy, ii < y_ + 0.5 * dy))

# assign value 1 to the cells
for ip in iip:
for jp in jjp:
mat_plot_canvas[ip, jp] = 1

return mat_plot_canvas

@staticmethod
def __make_yaxis(ylim, size, label_fmt: str = None) -> np.ndarray:

# workout data plot boundaries
y1, y2 = ylim

# workout width and height per cell of the canvas matrix
ii = np.linspace(y1, y2, size[1])

if label_fmt is None:
max_digits = 0
for i in ii:
if len(str(int(i))) > max_digits:
max_digits = len(str(int(i)))
length = max_digits + 4 # (potential) minus sign + max_length + decimal symbol + 2 decimal places
label_fmt = '{:' + str(int(length)) + '.2f}'
else:
length = len(label_fmt.format(0.1))

mat_yaxis = np.full(shape=(size[1], length + 1), fill_value=' ', dtype='<U1')
mat_yaxis[:, -1] = '┫'

for i in range(len(ii)):
mat_yaxis[i, 0:length] = np.array(list(label_fmt.format(ii[i])), dtype='<U1')

return mat_yaxis

@staticmethod
def __make_xaxis(xlim, size, label_fmt: str = None) -> np.ndarray:

jj = np.linspace(min(xlim), max(xlim), size[0])

if label_fmt is None:
max_digits = 0
for j in jj:
if len(str(int(j))) > max_digits:
max_digits = len(str(int(j)))
length = max_digits + 4 # (potential) minus sign + max_length + decimal symbol + 2 decimal places
label_fmt = '{:' + str(int(length)) + '.2f}'
else:
length = len(label_fmt.format(0.1))
list_x_tick_labels_exhaustive = [label_fmt.format(j) for j in jj]

dx_label = max([len(i) for i in list_x_tick_labels_exhaustive]) + 2

mat_xaxis = np.full(shape=(2, size[0]), fill_value=' ', dtype='<U1')
xaxis_label_index = np.arange(int(dx_label / 2), mat_xaxis.shape[1] - 0.5 * dx_label, dx_label, dtype=int)
xaxis_label_value = [list_x_tick_labels_exhaustive[i] for i in xaxis_label_index]
xaxis_label_tick = np.full(shape=(size[0],), fill_value='━', dtype='<U1')
for i in xaxis_label_index:
xaxis_label_tick[i] = '┳'

mat_xaxis[0, :] = xaxis_label_tick

for i, v in enumerate(' ' + ' '.join(xaxis_label_value) + ' '):
mat_xaxis[1, i] = v

return mat_xaxis

@staticmethod
def __assemble(mat_plot_canvas, mat_xaxis, mat_yaxis) -> np.ndarray:
mat_canvas = np.full_like(mat_plot_canvas, fill_value=' ', dtype='<U1')
mat_canvas[mat_plot_canvas > 0] = '*'

# construct figure matrix
mat_figure = np.full(
# shape=(mat_plot_canvas.shape[0] + mat_xaxis.shape[0], mat_yaxis.shape[1] + mat_plot_canvas.shape[1]),
shape=(mat_plot_canvas.shape[0] + mat_xaxis.shape[0], mat_plot_canvas.shape[1] + mat_yaxis.shape[1]),
fill_value=' ', dtype='<U1')

# assign canvas to figure
j1 = mat_yaxis.shape[1]
j2 = mat_yaxis.shape[1] + mat_plot_canvas.shape[1]
i1 = 0
i2 = mat_plot_canvas.shape[0]
mat_figure[i1:i2, j1:j2] = mat_canvas[::-1, :]

# assign yaxis to figure
j1 = 0
j2 = mat_yaxis.shape[1]
i1 = 0
i2 = mat_yaxis.shape[0]
mat_figure[i1:i2, j1:j2] = mat_yaxis[::-1, :]

# assign xaxis to figure
j1 = mat_yaxis.shape[1]
j2 = mat_yaxis.shape[1] + mat_xaxis.shape[1]
i1 = mat_canvas.shape[0]
i2 = mat_canvas.shape[0] + mat_xaxis.shape[0]
mat_figure[i1:i2, j1:j2] = mat_xaxis[:, :]

# final touches
i = mat_yaxis.shape[0]
j = mat_yaxis.shape[1] - 1
mat_figure[i, j] = '┗'

return mat_figure

@property
def size(self) -> Tuple[float, float]:
return self.__size

@size.setter
def size(self, v: Tuple[float, float]):
assert any([isinstance(v, tuple), isinstance(v, list)])
assert len(v) == 2
self.__size = v

@property
def xlim(self):
return self.__xlim

@xlim.setter
def xlim(self, v: Tuple[float, float]):
assert any([isinstance(v, tuple), isinstance(v, list)])
assert len(v) == 2

self.__xlim = v

@property
def ylim(self):
return self.__ylim

@ylim.setter
def ylim(self, v: Tuple[float, float]):
try:
assert all([isinstance(v, tuple), isinstance(v, list), len(v) == 2])
except:
raise ValueError('`ylim` should be a tuple with length equal to 2')

self.__ylim = v


def _test_asciiplot():
size = (80, 25)
xlim = (-2 * np.pi, 2 * np.pi)
ylim = (-1.1, 1.1)

aplot = AsciiPlot(size=size)

x = np.linspace(-2 * np.pi, 2 * np.pi, 50)
aplot.plot(
x=x,
y=np.sin(x),
xlim=xlim,
ylim=ylim,
).show()


if __name__ == '__main__':
_test_asciiplot()
Loading

0 comments on commit 5083e5b

Please sign in to comment.