Skip to content

Commit d909110

Browse files
authored
Merge pull request #42 from siftech/develop
v1.8.0
2 parents c503c8e + c64f541 commit d909110

File tree

116 files changed

+19670
-667
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+19670
-667
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,7 @@ gmon.out
315315
unsat.core
316316
.gitignore
317317
core.dimacs
318+
notebooks/saved-results/out
319+
**/*.bbl
320+
**/*.blg
321+
**/*.out

README.md

Lines changed: 292 additions & 158 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Version information."""
22

33
# The following line *must* be the last in the module, exactly as formatted:
4-
__version__ = "1.5.2"
4+
__version__ = "1.8.0"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Version information."""
22

33
# The following line *must* be the last in the module, exactly as formatted:
4-
__version__ = "1.7.0"
4+
__version__ = "1.8.0"

auxiliary_packages/funman_demo/src/funman_demo/example/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
ParameterSynthesisScenario,
1111
ParameterSynthesisScenarioResult,
1212
)
13-
from funman.search import ResultCombinedHandler
13+
from funman.utils.handlers import ResultCombinedHandler
14+
1415

1516
from ..plot import plot_parameter_space
1617

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import logging
2+
import os
3+
from typing import List, Optional
4+
5+
import matplotlib.animation as animation
6+
import matplotlib.pyplot as plt
7+
import numpy as np
8+
import pandas as pd
9+
import seaborn as sns
10+
from IPython.display import HTML
11+
from sklearn import preprocessing
12+
13+
from funman.server.query import FunmanResults
14+
15+
16+
def animate_heat_map(my_df, frames):
17+
fig = plt.figure()
18+
19+
vmin = my_df.min().min()
20+
vmax = my_df.max().max()
21+
# ax = sns.heatmap(data, vmin=0, vmax=1)
22+
# fig, ax = plt.subplots()
23+
# sns.heatmap(data, vmin=vmin, vmax=vmax, cmap="crest", ax=ax)
24+
25+
def init():
26+
# plt.clf()
27+
fig.clear()
28+
data = my_df.loc[0, :]
29+
ax = sns.heatmap(data, vmin=vmin, vmax=vmax, cmap="crest")
30+
ax.set_xlabel(data.columns[0][0])
31+
ax.set_ylabel(data.index.name)
32+
ax.set_title(data.columns[0][0])
33+
34+
def animate(i):
35+
# plt.clf()
36+
fig.clear()
37+
data = my_df.loc[i, :]
38+
# ax.set_data(data)
39+
ax = sns.heatmap(data, vmin=vmin, vmax=vmax, cmap="crest")
40+
ax.set_xlabel(data.columns[0][0])
41+
ax.set_ylabel(data.index.name)
42+
ax.set_title(f"{data.columns[0][0]}: time = {i}")
43+
44+
anim = animation.FuncAnimation(
45+
fig,
46+
animate,
47+
interval=1000,
48+
frames=frames,
49+
init_func=init,
50+
)
51+
52+
return anim
53+
54+
55+
def plot_spatial_timeseries(
56+
results: FunmanResults,
57+
variables: Optional[List[str]] = None,
58+
outdir=None,
59+
fps=1,
60+
):
61+
logging.getLogger("matplotlib.animation").setLevel(logging.ERROR)
62+
logging.getLogger("matplotlib.colorbar").setLevel(logging.ERROR)
63+
64+
df = results.dataframe(points=[results.parameter_space.true_points()[-1]])
65+
steps = len(df)
66+
parameters = results.model._parameter_names()
67+
vars = results.model._state_var_names()
68+
to_drop = (
69+
parameters
70+
+ ["id", "label"]
71+
+ [v for v in vars if variables is not None and v not in variables]
72+
)
73+
df = df.drop(columns=to_drop)
74+
75+
# x = df.values #returns a numpy array
76+
# min_max_scaler = preprocessing.MinMaxScaler()
77+
# standard_scaler = preprocessing.StandardScaler()
78+
# x_scaled = min_max_scaler.fit_transform(x)
79+
# # x_scaled = standard_scaler.fit_transform(x)
80+
# df = pd.DataFrame(x_scaled, columns =df.columns)
81+
82+
df.columns = df.columns.str.split("_", expand=True)
83+
df = df.stack([1])
84+
df.index = df.index.set_names(["time"] + [df.columns[0][0]])
85+
86+
anim_h = animate_heat_map(df, steps)
87+
if outdir:
88+
anim_h.save(
89+
os.path.join(outdir, "h.gif"),
90+
writer=animation.PillowWriter(fps=fps),
91+
)
92+
hh = HTML(anim_h.to_jshtml())
93+
dh = df.unstack().diff().fillna(0).stack([1]).rename(columns={"h": "dh"})
94+
anim_dh = animate_heat_map(dh, steps)
95+
if outdir:
96+
anim_dh.save(
97+
os.path.join(outdir, "dh.gif"),
98+
writer=animation.PillowWriter(fps=fps),
99+
)
100+
hdh = HTML(anim_dh.to_jshtml())
101+
102+
return hh, hdh, anim_h, anim_dh

auxiliary_packages/funman_demo/src/funman_demo/parameter_space_plotter.py

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def __init__(
2626
alpha=0.2,
2727
plot_points=False,
2828
parameters=None,
29+
dpi=100,
2930
):
3031
if isinstance(parameter_space, ParameterSpace):
3132
self.ps = parameter_space
@@ -55,20 +56,30 @@ def __init__(
5556
Line2D([0], [0], color="g", lw=4, alpha=alpha),
5657
Line2D([0], [0], color="r", lw=4, alpha=alpha),
5758
]
59+
self.dpi = dpi
5860

5961
def computeBounds(self, interval: Interval = Interval(lb=-2000, ub=2000)):
6062
box = Box(bounds={p: interval for p in self.parameters})
6163
return box
6264

63-
def initialize_figure(self):
65+
def map_param_idx_to_plot_loc(self, i, j, plot_diagonal):
66+
if plot_diagonal:
67+
return i, j
68+
elif i == 0 or j == self.dim - 1:
69+
return None, None
70+
else:
71+
return i - 1, j
72+
73+
def initialize_figure(self, plot_diagonal):
6474
if self.dim == 0:
6575
return
6676

77+
dim_to_plot = self.dim if plot_diagonal else self.dim - 1
6778
fig, axs = plt.subplots(
68-
self.dim,
69-
self.dim,
79+
dim_to_plot,
80+
dim_to_plot,
7081
squeeze=False,
71-
dpi=600,
82+
dpi=self.dpi,
7283
figsize=(10, 10),
7384
)
7485
self.fig = fig
@@ -89,43 +100,74 @@ def initialize_figure(self):
89100

90101
self.fig.tight_layout(pad=3.0)
91102
self.data = [[None] * self.dim] * self.dim
103+
92104
for i in range(self.dim):
93105
for j in range(self.dim):
94-
if j > i:
95-
axs[i, j].axis("off")
106+
i_coord, j_coord = self.map_param_idx_to_plot_loc(
107+
i, j, plot_diagonal
108+
)
109+
if i_coord is None or j_coord is None:
110+
continue
111+
112+
if j_coord > i_coord:
113+
axs[i_coord, j_coord].axis("off")
96114
else:
97-
(self.data[i][j],) = self.axs[i, j].plot([], [])
98-
axs[i, j].set_xlabel(f"{self.parameters[i]}")
99-
axs[i, j].set_ylabel(f"{self.parameters[j]}")
115+
(self.data[i][j],) = self.axs[i_coord, j_coord].plot(
116+
[], []
117+
)
118+
axs[i_coord, j_coord].set_xlabel(f"{self.parameters[i]}")
119+
axs[i_coord, j_coord].set_ylabel(f"{self.parameters[j]}")
100120
self.fig.suptitle(self.title)
101121
plt.legend(self.custom_lines, ["true", "false"])
102122

103-
def plot(self, show=False):
104-
self.initialize_figure()
123+
def plot(self, show=False, plot_diagonal=False):
124+
self.initialize_figure(plot_diagonal)
105125
t = "true"
106126
f = "false"
107127
for b in self.ps.false_boxes:
108-
self.plotNDBox(b, self.color_map[f])
128+
self.plotNDBox(b, self.color_map[f], plot_diagonal=plot_diagonal)
109129
for b in self.ps.true_boxes:
110-
self.plotNDBox(b, self.color_map[t])
130+
self.plotNDBox(b, self.color_map[t], plot_diagonal=plot_diagonal)
111131
if self.plot_points:
112132
for p in self.ps.false_points():
113-
self.plot_add_point(p, self.color_map[f], self.shape_map[f])
133+
self.plot_add_point(
134+
p,
135+
self.color_map[f],
136+
self.shape_map[f],
137+
plot_diagonal=plot_diagonal,
138+
)
114139
true_points = self.ps.true_points()
115140
for p in true_points:
116-
self.plot_add_point(p, self.color_map[t], self.shape_map[t])
141+
self.plot_add_point(
142+
p,
143+
self.color_map[t],
144+
self.shape_map[t],
145+
plot_diagonal=plot_diagonal,
146+
)
117147
if show:
118148
plt.show(block=False)
119149

120-
def plot_add_point(self, point: Point, color="r", shape="x", alpha=0.9):
150+
def plot_add_point(
151+
self,
152+
point: Point,
153+
color="r",
154+
shape="x",
155+
alpha=0.9,
156+
plot_diagonal=False,
157+
):
121158
for i in range(self.dim):
122159
for j in range(self.dim):
123-
if i < j:
160+
i_coord, j_coord = self.map_param_idx_to_plot_loc(
161+
i, j, plot_diagonal
162+
)
163+
if i_coord is None or j_coord is None:
164+
continue
165+
if j_coord > i_coord:
124166
continue
125167
yval = (
126168
point.values[self.parameters[j]] if self.dim > 1 else 0.0
127169
)
128-
self.axs[i, j].scatter(
170+
self.axs[i_coord, j_coord].scatter(
129171
point.values[self.parameters[i]],
130172
yval,
131173
color=color,
@@ -136,17 +178,23 @@ def plot_add_point(self, point: Point, color="r", shape="x", alpha=0.9):
136178
# self.fig.canvas.draw()
137179
# self.fig.canvas.flush_events()
138180

139-
def plotNDBox(self, box, color="g", alpha=0.2):
181+
def plotNDBox(self, box, color="g", alpha=0.2, plot_diagonal=False):
140182
for i in range(self.dim):
141183
for j in range(self.dim):
142-
if i < j:
184+
i_coord, j_coord = self.map_param_idx_to_plot_loc(
185+
i, j, plot_diagonal
186+
)
187+
if i_coord is None or j_coord is None:
143188
continue
189+
if j_coord > i_coord:
190+
continue
191+
144192
x_limits = box.bounds[self.parameters[i]]
145193
y_limits = box.bounds[self.parameters[j]]
146194

147195
if i == j:
148196
# Plot a line segment
149-
self.axs[i, j].plot(
197+
self.axs[i_coord, j_coord].plot(
150198
[x_limits.lb, x_limits.ub],
151199
[x_limits.lb, x_limits.ub],
152200
color=color,
@@ -162,7 +210,7 @@ def plotNDBox(self, box, color="g", alpha=0.2):
162210
x = np.linspace(
163211
float(x_limits.lb), float(x_limits.ub), 1000
164212
)
165-
self.axs[i, j].fill_between(
213+
self.axs[i_coord, j_coord].fill_between(
166214
x,
167215
y_limits.lb,
168216
y_limits.ub,

auxiliary_packages/funman_demo/src/funman_demo/plot.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import json
22
import logging
3+
from typing import Dict
34

45
import matplotlib.pyplot as plt
56
from IPython.display import clear_output
67
from matplotlib.lines import Line2D
78

8-
from funman import Box, Point
9+
from funman import Box, Parameter, Point
910
from funman.representation.parameter_space import ParameterSpace
1011

1112
l = logging.getLogger(__file__)
@@ -65,3 +66,37 @@ def plot_cached_search(search_path, alpha: float = 0.2):
6566
ParameterSpace(true_boxes, false_boxes, true_points, false_points),
6667
alpha=alpha,
6768
)
69+
70+
71+
def summarize_results(variables, results, ylabel="Height"):
72+
points = results.points()
73+
boxes = results.parameter_space.boxes()
74+
75+
l.info("*" * 80)
76+
l.info("*" * 80)
77+
l.info("* Analysis Summary ")
78+
l.info("*" * 80)
79+
l.info(
80+
f"{len(points)} Points (+:{len(results.parameter_space.true_points())}, -:{len(results.parameter_space.false_points())}), {len(boxes)} Boxes (+:{len(results.parameter_space.true_boxes)}, -:{len(results.parameter_space.false_boxes)})"
81+
)
82+
if points and len(points) > 0:
83+
point: Point = points[-1]
84+
parameters: Dict[Parameter, float] = results.point_parameters(point)
85+
results.plot(
86+
variables=variables,
87+
label_marker={"true": ",", "false": ","},
88+
xlabel="Time",
89+
ylabel=ylabel,
90+
legend=variables,
91+
label_color={"true": "g", "false": "r"},
92+
)
93+
parameter_values = {p: point.values[p.name] for p in parameters}
94+
l.info(f"Parameters = {parameter_values}")
95+
l.info(parameters)
96+
l.info(results.dataframe([point]))
97+
else:
98+
# if there are no points, then we have a box that we found without needing points
99+
l.info(f"Found box with no points")
100+
box = boxes[0]
101+
l.info(json.dumps(box.explain(), indent=4))
102+
l.info("*" * 80)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Version information."""
22

33
# The following line *must* be the last in the module, exactly as formatted:
4-
__version__ = "1.7.0"
4+
__version__ = "1.8.0"

0 commit comments

Comments
 (0)