SignaturePlote, import instead of attach, jupyter friendly plots
This commit is contained in:
parent
4d549c2dcb
commit
ee58512534
@ -1,16 +1,31 @@
|
||||
#!/usr/bin/env sage -python
|
||||
|
||||
import numpy as np
|
||||
import itertools as it
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
import warnings
|
||||
import re
|
||||
import inspect
|
||||
|
||||
from typing import Iterable
|
||||
from collections import Counter
|
||||
from sage.arith.functions import LCM_list
|
||||
import importlib
|
||||
|
||||
def import_sage(module_name):
|
||||
|
||||
importlib.invalidate_caches()
|
||||
sage_name = module_name + ".sage"
|
||||
python_name = module_name + ".sage.py"
|
||||
|
||||
if os.path.isfile(sage_name):
|
||||
os.system('sage --preparse {}'.format(sage_name));
|
||||
os.system('mv {} {}.py'.format(python_name, module_name))
|
||||
|
||||
if module_name in sys.modules:
|
||||
return importlib.reload(sys.modules[module_name])
|
||||
return importlib.import_module(module_name, package=None)
|
||||
sig = import_sage('signature')
|
||||
|
||||
|
||||
# #############################################################################
|
||||
# 9.11 (9.8)
|
||||
# 9.15 (9.9)
|
||||
PLOTS_DIR = "plots"
|
||||
@ -18,8 +33,8 @@ PLOTS_DIR = "plots"
|
||||
class CableSummand():
|
||||
|
||||
def __init__(self, knot_as_k_values):
|
||||
self.knot_as_k_values = knot_as_k_values
|
||||
|
||||
self.knot_as_k_values = knot_as_k_values
|
||||
self.knot_description = self.get_summand_descrption(knot_as_k_values)
|
||||
self.signature_as_function_of_theta = \
|
||||
self.get_summand_signature_as_theta_function()
|
||||
@ -90,14 +105,14 @@ class CableSummand():
|
||||
results.append((e * ksi, -1 * sgn(k_n)))
|
||||
results.append((1 - e * ksi, 1 * sgn(k_n)))
|
||||
|
||||
return SignatureFunction(values=results)
|
||||
return sig.SignatureFunction(values=results)
|
||||
|
||||
@classmethod
|
||||
def get_satellite_part(cls, *knot_as_k_values, theta=0):
|
||||
patt_k = knot_as_k_values[-1]
|
||||
ksi = 1/(2 * abs(patt_k) + 1)
|
||||
|
||||
satellite_part = SignatureFunction()
|
||||
satellite_part = sig.SignatureFunction()
|
||||
# For each knot summand consider k values in reversed order,
|
||||
# ommit k value for pattern.
|
||||
for layer_num, k in enumerate(knot_as_k_values[:-1][::-1]):
|
||||
@ -120,7 +135,7 @@ class CableSummand():
|
||||
for a in range(k)})
|
||||
counter.update(Counter({(2 * a + 1)/(2 * q) : sgn(j)
|
||||
for a in range(k + 1, q)}))
|
||||
return SignatureFunction(counter=counter)
|
||||
return sig.SignatureFunction(counter=counter)
|
||||
|
||||
def get_summand_signature_as_theta_function(self):
|
||||
knot_as_k_values = self.knot_as_k_values
|
||||
@ -168,7 +183,8 @@ class CableSummand():
|
||||
if save_path is not None:
|
||||
file_name = self.get_file_name_for_summand_plot(theta)
|
||||
save_path = os.path.join(save_path, file_name)
|
||||
pp.plot_sum_with_other(sp, title=title, save_path=save_path)
|
||||
sig.SignaturePloter.plot_sum_of_two(pp, sp, title=title,
|
||||
save_path=save_path)
|
||||
|
||||
def plot_summand(self):
|
||||
range_limit = min(self.knot_as_k_values[-1] + 1, 3)
|
||||
@ -178,10 +194,12 @@ class CableSummand():
|
||||
class CableSum():
|
||||
|
||||
def __init__(self, knot_sum):
|
||||
|
||||
self.knot_sum_as_k_valus = knot_sum
|
||||
self.knot_description = self.get_knot_descrption(knot_sum)
|
||||
self.patt_k_list = [abs(i[-1]) for i in knot_sum]
|
||||
self.patt_q_list = [2 * i + 1 for i in self.patt_k_list]
|
||||
|
||||
if any(n not in Primes() for n in self.patt_q_list):
|
||||
msg = "Incorrect k- or q-vector. This implementation assumes that"\
|
||||
+ " all last q values are prime numbers.\n" + \
|
||||
@ -234,7 +252,8 @@ class CableSum():
|
||||
file_name = re.sub(r', ', '_', str(thetas))
|
||||
file_name = re.sub(r'[\[\]]', '', str(file_name))
|
||||
file_path = os.path.join(save_path, file_name)
|
||||
pp.plot_sum_with_other(sp, title=title, save_path=file_path)
|
||||
sig.SignaturePloter.plot_sum_of_two(pp, sp, title=title,
|
||||
save_path=file_path)
|
||||
|
||||
|
||||
if save_path is not None:
|
||||
@ -249,11 +268,12 @@ class CableSum():
|
||||
sf_list.append(sf_list[-1])
|
||||
# sf_list.append(sf_list[-1])
|
||||
|
||||
SignatureFunction.plot_many(*sf_list)
|
||||
sig.SignaturePloter.plot_many(*sf_list)
|
||||
# pp, sp, sf = knot.signature_as_function_of_theta(thetas[i])
|
||||
# (pp + sp) = sp.plot
|
||||
#
|
||||
# pp.plot_sum_with_other(sp, title=title, save_path=file_path)
|
||||
# sig.SignatureFunction.plot_sum_of_two(pp, sp, title=title,
|
||||
# save_path=file_path)
|
||||
|
||||
|
||||
|
||||
@ -311,8 +331,8 @@ class CableSum():
|
||||
verbose = kwargs['verbose']
|
||||
thetas = self.parse_thetas(*thetas)
|
||||
|
||||
satellite_part = SignatureFunction()
|
||||
pattern_part = SignatureFunction()
|
||||
satellite_part = sig.SignatureFunction()
|
||||
pattern_part = sig.SignatureFunction()
|
||||
|
||||
# for each cable knot (summand) in cable sum apply theta
|
||||
for i, knot in enumerate(self.knot_summands):
|
||||
@ -357,7 +377,7 @@ class CableSum():
|
||||
shifted_thetas = [shift * th for th in thetas]
|
||||
pp, sp, sf= self.signature_as_function_of_theta(*shifted_thetas)
|
||||
limit = 5 + np.count_nonzero(shifted_thetas)
|
||||
extremum = abs(sf.extremum(limit=limit))
|
||||
extremum = abs(sf.extremum(limit=limit)[1])
|
||||
if shift > 1:
|
||||
print(shifted_thetas, end=" ")
|
||||
print(extremum)
|
||||
@ -509,7 +529,7 @@ CableSum.get_signature_as_function_of_theta.__doc__ = \
|
||||
k - parameters for a cable: parameters k_i (i=1,.., n-1) for satelit knots
|
||||
T(2, 2k_i + 1) and - the last one - k_n for a pattern knot T(2, 2k_n + 1).
|
||||
Returns a function that will take theta vector as an argument and return
|
||||
an object SignatureFunction.
|
||||
an object sig.SignatureFunction.
|
||||
|
||||
To calculate signature function for a cable sum and a theta values vector,
|
||||
use as below.
|
||||
@ -555,7 +575,7 @@ CableSum.get_signature_as_function_of_theta.__doc__ = \
|
||||
|
||||
get_summand_signture_function_docsting = \
|
||||
"""
|
||||
This function returns SignatureFunction for previously defined single
|
||||
This function returns sig.SignatureFunction for previously defined single
|
||||
cable T_(2, q) and a theta given as an argument.
|
||||
The cable was defined by calling function
|
||||
get_summand_signature_as_theta_function(*arg)
|
||||
@ -570,7 +590,7 @@ signature_as_function_of_theta_docstring = \
|
||||
"""
|
||||
Arguments:
|
||||
|
||||
Returns object of SignatureFunction class for a previously defined
|
||||
Returns object of sig.SignatureFunction class for a previously defined
|
||||
connected sum of len(arg) cables.
|
||||
Accept len(arg) arguments: for each cable one theta parameter.
|
||||
If call with no arguments, all theta parameters are set to be 0.
|
||||
@ -583,7 +603,7 @@ signature_as_function_of_theta_docstring = \
|
||||
# T(2, q_n) is a pattern knot for a single cable from a cable sum
|
||||
# theta: twist/character for the cable (value form v vector)
|
||||
# Return:
|
||||
# SignatureFunction created for pattern signature function
|
||||
# sig.SignatureFunction created for pattern signature function
|
||||
# for a given cable and theta/character
|
||||
# Based on:
|
||||
# Proposition 9.8. in Twisted Blanchfield Pairing
|
||||
@ -596,6 +616,6 @@ signature_as_function_of_theta_docstring = \
|
||||
# n integers that encode a single cable, i.e.
|
||||
# values of q_i for T(2,q_0; 2,q_1; ... 2, q_n)
|
||||
# Return:
|
||||
# a function that returns SignatureFunction for this single cable
|
||||
# a function that returns sig.SignatureFunction for this single cable
|
||||
# and a theta given as an argument
|
||||
# """
|
||||
|
164
signature.sage
164
signature.sage
@ -1,20 +1,31 @@
|
||||
#!/usr/bin/env sage -python
|
||||
import numpy as np
|
||||
import itertools as it
|
||||
from typing import Iterable
|
||||
|
||||
from collections import Counter
|
||||
from sage.arith.functions import LCM_list
|
||||
import warnings
|
||||
import re
|
||||
import matplotlib.pyplot as plt
|
||||
import inspect
|
||||
from PIL import Image
|
||||
from pathlib import Path
|
||||
import warnings
|
||||
|
||||
# 9.11 (9.8)
|
||||
# 9.15 (9.9)
|
||||
|
||||
|
||||
class SignatureFunction():
|
||||
JUPYTER = 'ipykernel'
|
||||
IPy_TERMINAL = 'IPython'
|
||||
|
||||
def get_ipython_info():
|
||||
if JUPYTER in sys.modules:
|
||||
return JUPYTER
|
||||
elif IPy_TERMINAL in sys.modules:
|
||||
return IPy_TERMINAL
|
||||
return False
|
||||
|
||||
global ipython_info
|
||||
ipython_info = get_ipython_info()
|
||||
|
||||
|
||||
class SignatureFunction:
|
||||
|
||||
def __init__(self, values=None, counter=None, plot_title=''):
|
||||
|
||||
@ -104,35 +115,43 @@ class SignatureFunction():
|
||||
counter = Counter({mod_one(2 * k) : v for k, v in items if k >= 1/2})
|
||||
return SignatureFunction(counter=counter)
|
||||
|
||||
|
||||
def is_zero_everywhere(self):
|
||||
return not any(self.jumps_counter.values())
|
||||
|
||||
|
||||
def extremum(self, limit=None):
|
||||
max = 0
|
||||
def extremum(self, limit=math.inf):
|
||||
max_point = (0, 0)
|
||||
current = 0
|
||||
items = sorted(self.jumps_counter.items())
|
||||
for arg, jump in items:
|
||||
current += 2 * jump
|
||||
assert current == self(arg) + jump
|
||||
if abs(current) > abs(max):
|
||||
max = current
|
||||
if limit is not None:
|
||||
if abs(max) > limit:
|
||||
break
|
||||
return max
|
||||
if abs(current) > abs(max_point[1]):
|
||||
max_point = (arg, current)
|
||||
if abs(current) > limit:
|
||||
break
|
||||
return max_point
|
||||
|
||||
def total_sign_jump(self):
|
||||
# Total signature jump is the sum of all jumps.
|
||||
return sum([j[1] for j in sorted(self.jumps_counter.items())])
|
||||
|
||||
@staticmethod
|
||||
def plot_many(*sf_list, save_path=None, title='',):
|
||||
def plot(self, *args, **kargs):
|
||||
SignaturePloter.plot(self, *args, **kargs)
|
||||
|
||||
|
||||
class SignaturePloter:
|
||||
|
||||
@classmethod
|
||||
def plot_many(cls, *sf_list, save_path=None, title='',):
|
||||
|
||||
axes_num = len(sf_list)
|
||||
if axes_num > 36:
|
||||
sf_list = sf_list[36]
|
||||
axes_num = 36
|
||||
msg = "To many functions for the plot were given. "
|
||||
msg += "Only 36 can be plotted "
|
||||
warnings.warn(msg)
|
||||
|
||||
# print war, set val in conf
|
||||
rows = ceil(sqrt(axes_num))
|
||||
cols = ceil(axes_num/rows)
|
||||
@ -146,55 +165,21 @@ class SignatureFunction():
|
||||
ax=axes_matrix[row][col],
|
||||
title=sf.plot_title)
|
||||
|
||||
fig.suptitle(title)
|
||||
plt.tight_layout()
|
||||
save_path = save_path or os.path.join(os.getcwd(),"tmp.png")
|
||||
save_path = Path(save_path).with_suffix('.png')
|
||||
|
||||
plt.savefig(save_path)
|
||||
plt.close()
|
||||
image = Image.open(save_path)
|
||||
image.show()
|
||||
cls.show_and_save(save_path)
|
||||
|
||||
return
|
||||
@classmethod
|
||||
def plot_sum_of_two(cls, sf1, sf2, save_path=None, title=''):
|
||||
|
||||
sf = sf1 + sf2
|
||||
fig, axes_matrix = plt.subplots(2, 2, sharey=True, figsize=(10,5))
|
||||
|
||||
sf1.plot(subplot=True,
|
||||
ax=axes_matrix[1][0],
|
||||
color='red',
|
||||
linestyle='dotted')
|
||||
|
||||
sf2.plot(subplot=True,
|
||||
ax=axes_matrix[0][0],
|
||||
color='black')
|
||||
|
||||
sf3.plot(subplot=True,
|
||||
ax=axes_matrix[1][1],
|
||||
alpha=0.3)
|
||||
|
||||
fig.suptitle(title)
|
||||
|
||||
plt.tight_layout()
|
||||
save_path = save_path or os.path.join(os.getcwd(),"tmp.png")
|
||||
save_path = Path(save_path).with_suffix('.png')
|
||||
|
||||
plt.savefig(save_path)
|
||||
plt.close()
|
||||
image = Image.open(save_path)
|
||||
image.show()
|
||||
|
||||
def plot_sum_with_other(self, other,
|
||||
save_path=None, title=''):
|
||||
tp = self
|
||||
up = other
|
||||
sf = tp + up
|
||||
|
||||
fig, axes_matrix = plt.subplots(2, 2, sharey=True,
|
||||
figsize=(10,5))
|
||||
|
||||
tp.plot(subplot=True,
|
||||
ax=axes_matrix[0][1])
|
||||
|
||||
up.plot(subplot=True,
|
||||
sf2.plot(subplot=True,
|
||||
ax=axes_matrix[1][0],
|
||||
color='red',
|
||||
linestyle='dotted')
|
||||
@ -203,11 +188,11 @@ class SignatureFunction():
|
||||
ax=axes_matrix[0][0],
|
||||
color='black')
|
||||
|
||||
tp.plot(subplot=True,
|
||||
sf1.plot(subplot=True,
|
||||
ax=axes_matrix[1][1],
|
||||
alpha=0.3)
|
||||
|
||||
up.plot(subplot=True,
|
||||
sf2.plot(subplot=True,
|
||||
ax=axes_matrix[1][1],
|
||||
color='red', alpha=0.3,
|
||||
linestyle='dotted')
|
||||
@ -218,22 +203,12 @@ class SignatureFunction():
|
||||
alpha=0.7,)
|
||||
|
||||
fig.suptitle(title)
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
save_path = save_path or os.path.join(os.getcwd(),"tmp.png")
|
||||
save_path = Path(save_path)
|
||||
save_path = save_path.with_suffix('.png')
|
||||
cls.show_and_save(save_path)
|
||||
|
||||
|
||||
# print(save_as)
|
||||
|
||||
plt.savefig(save_path)
|
||||
plt.close()
|
||||
image = Image.open(save_path)
|
||||
image.show()
|
||||
|
||||
def plot(self, subplot=False, ax=None, save_as='sf',
|
||||
@classmethod
|
||||
def plot(cls, sf, subplot=False, ax=None, save_path=None,
|
||||
title="",
|
||||
alpha=1,
|
||||
color='blue',
|
||||
@ -243,8 +218,8 @@ class SignatureFunction():
|
||||
if ax is None:
|
||||
fig, ax = plt.subplots(1, 1)
|
||||
|
||||
keys = sorted(self.jumps_counter.keys())
|
||||
y = [self(k) + self.jumps_counter[k] for k in keys]
|
||||
keys = sorted(sf.jumps_counter.keys())
|
||||
y = [sf(k) + sf.jumps_counter[k] for k in keys]
|
||||
xmax = keys[1:]
|
||||
xmin = keys[:-1]
|
||||
|
||||
@ -255,20 +230,37 @@ class SignatureFunction():
|
||||
if subplot:
|
||||
return ax
|
||||
|
||||
save_as += ".png"
|
||||
plt.savefig(save_as)
|
||||
plt.close()
|
||||
image = Image.open(save_as)
|
||||
image.show()
|
||||
cls.show_and_save(save_path)
|
||||
|
||||
def step_function_data(self):
|
||||
@staticmethod
|
||||
def show_and_save(save_path):
|
||||
|
||||
if save_path is not None:
|
||||
save_path = Path(save_path)
|
||||
save_path = save_path.with_suffix('.png')
|
||||
plt.savefig(save_path)
|
||||
|
||||
if ipython_info == JUPYTER:
|
||||
plt.show()
|
||||
|
||||
elif True: # save_path is None:
|
||||
plt.savefig('tmp.png')
|
||||
plt.close()
|
||||
image = Image.open('tmp.png')
|
||||
image.show()
|
||||
# msg = "For interactive shell set save_path."
|
||||
# warnings.warn(msg)
|
||||
|
||||
@staticmethod
|
||||
def step_function_data(sf):
|
||||
# Transform the signature jump data to a format understandable
|
||||
# by the plot function.
|
||||
result = [(k, self.sf(k) + self.jumps_counter[k])
|
||||
for k in sorted(self.jumps_counter.keys())]
|
||||
result = [(k, sf.sf(k) + sf.jumps_counter[k])
|
||||
for k in sorted(sf.jumps_counter.keys())]
|
||||
return result
|
||||
|
||||
def tikz_plot(self, save_as):
|
||||
@staticmethod
|
||||
def tikz_plot(sf, save_as):
|
||||
plt_sin = plot(sin(x), (x, 0, 2*pi))
|
||||
# plt_sin.show()
|
||||
plt_sin.save("MyPic.pdf")
|
||||
|
Loading…
Reference in New Issue
Block a user