diff --git a/data/Fig1-designProcess/blend1Subset.pickle b/data/Fig1-designProcess/blend1Subset.pickle index 16f85c8..09c09e8 100644 Binary files a/data/Fig1-designProcess/blend1Subset.pickle and b/data/Fig1-designProcess/blend1Subset.pickle differ diff --git a/data/Fig1-designProcess/blend2Subset.pickle b/data/Fig1-designProcess/blend2Subset.pickle index b7bfdfd..f3d08f4 100644 Binary files a/data/Fig1-designProcess/blend2Subset.pickle and b/data/Fig1-designProcess/blend2Subset.pickle differ diff --git a/data/Fig1-designProcess/blend3Subset.pickle b/data/Fig1-designProcess/blend3Subset.pickle index 06e8487..a1589fc 100644 Binary files a/data/Fig1-designProcess/blend3Subset.pickle and b/data/Fig1-designProcess/blend3Subset.pickle differ diff --git a/data/Fig1-designProcess/distinct1Subset.pickle b/data/Fig1-designProcess/distinct1Subset.pickle index bda0d25..e90f19b 100644 Binary files a/data/Fig1-designProcess/distinct1Subset.pickle and b/data/Fig1-designProcess/distinct1Subset.pickle differ diff --git a/data/Fig1-designProcess/distinct2Subset.pickle b/data/Fig1-designProcess/distinct2Subset.pickle index 3911e27..0e1250d 100644 Binary files a/data/Fig1-designProcess/distinct2Subset.pickle and b/data/Fig1-designProcess/distinct2Subset.pickle differ diff --git a/data/Fig1-designProcess/distinct3Subset.pickle b/data/Fig1-designProcess/distinct3Subset.pickle index 8ad06e1..bda92b8 100644 Binary files a/data/Fig1-designProcess/distinct3Subset.pickle and b/data/Fig1-designProcess/distinct3Subset.pickle differ diff --git a/data/Fig1-designProcess/distinctSubset.pickle b/data/Fig1-designProcess/distinctSubset.pickle index 9c882aa..934cc4b 100644 Binary files a/data/Fig1-designProcess/distinctSubset.pickle and b/data/Fig1-designProcess/distinctSubset.pickle differ diff --git a/data/Fig1-designProcess/fullData.pickle b/data/Fig1-designProcess/fullData.pickle index 29b4a65..2685960 100644 Binary files a/data/Fig1-designProcess/fullData.pickle and b/data/Fig1-designProcess/fullData.pickle differ diff --git a/data/Fig1-designProcess/hullSubset.pickle b/data/Fig1-designProcess/hullSubset.pickle index b5f796e..6c7bb27 100644 Binary files a/data/Fig1-designProcess/hullSubset.pickle and b/data/Fig1-designProcess/hullSubset.pickle differ diff --git a/data/Fig1-designProcess/outliersSubset.pickle b/data/Fig1-designProcess/outliersSubset.pickle index db87549..2d60e6f 100644 Binary files a/data/Fig1-designProcess/outliersSubset.pickle and b/data/Fig1-designProcess/outliersSubset.pickle differ diff --git a/data/solverData.csv b/data/solverData.csv index 4b69f2d..63126d2 100644 --- a/data/solverData.csv +++ b/data/solverData.csv @@ -107,3 +107,147 @@ Uni-criterion: clusterCenters,greedySwap,1000,2,10,0.13878262508660555,0.7724079 "Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,7,0.1945001189596951,0.0 "Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,7,0.18785801599733531,0.0 "Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,7,0.234673575963825,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,0.29593419295269996,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.11445782298687845,-77.13353928048035 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.5462852430064231,-74.18261659032585 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,16.019615472992882,-39.956777992395615 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.961098090047017,-71.3535755814987 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,17.308373406063765,-76.92932448798969 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,16,0.10311844199895859,-36.98853938692782 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,40,0.3425103520276025,-55.53023413167705 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,102,0.7111876929411665,-77.72499108526614 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.17156568495556712,-107.85032842123348 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.009137309971265495,-59.99163302732708 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.28689464705530554,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.07565713091753423,-76.90150167654883 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.33772983809467405,-82.65893651396253 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.733736847061664,-37.72502949783789 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,16.34970149002038,-79.21528178454805 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,16.09934757091105,-87.1484395780551 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,21,0.09933742694556713,-48.916226463106035 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,18,0.07778958394192159,-52.25319459589197 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,92,0.4698902699165046,-86.11815292551535 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,0.3114050959702581,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.1782841000240296,-94.00493289823834 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.6240650089457631,-81.66286493321189 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.76467304804828,-36.356196781059154 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,17.084750175010413,-78.89219470658081 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,18.41927482408937,-86.71818903727858 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,0.9344452220248058,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.8697499780682847,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.4994492910336703,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.4910243459744379,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,9,0.4479509260272607,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,9,0.7013822080334648,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,9,0.7932263310067356,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.925686597940512,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.9141074389917776,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.9515322380466387,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.8977055459981784,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,0.8896270530531183,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,1.3545968279941007,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1011312199989334,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8075686269439757,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7807131060399115,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.9366903710179031,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.150744732003659,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1362005930859596,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6776644670171663,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8283384050009772,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7767721880227327,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1211024429649115,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.1975002819672227,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8234556920360774,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7040190550033003,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.7956955870613456,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6690607069758698,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6585186719894409,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.6739458279917017,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.39736516401171684,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.8139416560297832,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.4658096390776336,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.5328066080110148,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.40911367000080645,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.42375491897109896,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,0.4381504019256681,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.0618235199945047,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.858548079035245,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.9225411330116913,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8708883179351687,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.59070663806051,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.6839401100296527,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.401693034917116,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.6874031629413366,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.7578133980277926,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.5088547869818285,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.169300428009592,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.232280447962694,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.1939020979916677,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.139898219029419,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.007311812019907,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.013121727039106,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.9959770779823884,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.232953047961928,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.2974324349779636,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.105868001934141,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.038483888027258,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.2182905660010874,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.2297344179823995,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.181866207974963,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.459757408942096,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.0248638410121202,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.8204639760078862,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.1470516480039805,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.907505503972061,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.873534856014885,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.7429639380425215,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.8942721990169957,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.134770376025699,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,1.9120049610501155,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.98742147104349,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.976412029005587,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.9450863489182666,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.081287116976455,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.7693268969887868,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8417827270459384,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.855016679968685,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8780118320137262,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.8611697829328477,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.961038665031083,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.2737037639599293,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.3527815849520266,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.2911710800835863,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.5750179030001163,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.1241388369817287,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.108717106981203,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,2.9237201779615134,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.1779711049748585,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.0755136230727658,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.065400000079535,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,8,3.2507090859580785,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.2701174030080438,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.5799345769919455,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.3197142069693655,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.446158067905344,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.5796150349779055,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,3.578337203944102,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,3.711465527070686,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,11,4.2906140179838985,0.0 +"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,10,3.549799660919234,0.0 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.06814886396750808,-89.60162497757574 +"Uni-criterion: sum, outlierness",greedySwap,200,2,40,36.6902008849429,-89.60162497757574 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.3224127379944548,-79.90049127593495 +"Uni-criterion: distinctness, distances",greedySwap,200,2,60,36.83346623403486,-80.79567585790252 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,15.037519195000641,-37.37670531499123 +"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,50.97084774100222,-39.22812364018983 +"Multi-criterion: 10*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,53.80880820809398,-76.04688048633925 +"Multi-criterion: 1*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,53.854620625963435,-85.06005136858656 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,10,0.04771749395877123,-38.18019263929493 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,52,0.22991829796228558,-58.48640809913543 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,87,0.42976776498835534,-81.60528780506851 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,23,4.512196074007079,-47.91799174414664 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,27,5.162200314924121,-55.62985637521753 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,88,17.476347186020575,-81.49231730696414 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,19,3.7761652149492875,-46.45876245484051 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,31,6.059022648027167,-56.28867409761743 +"Uni-criterion: distinctness, distances",greedyMixed,200,2,52,9.988744632923044,-68.26740153361762 diff --git a/figures/Fig1-designProcess/blend.pdf b/figures/Fig1-designProcess/blend.pdf index 7e08bba..7e84917 100644 Binary files a/figures/Fig1-designProcess/blend.pdf and b/figures/Fig1-designProcess/blend.pdf differ diff --git a/figures/Fig1-designProcess/express.pdf b/figures/Fig1-designProcess/express.pdf index d28aeaa..1c493fc 100644 Binary files a/figures/Fig1-designProcess/express.pdf and b/figures/Fig1-designProcess/express.pdf differ diff --git a/figures/Fig1-designProcess/tune.pdf b/figures/Fig1-designProcess/tune.pdf index c401764..4daa3ad 100644 Binary files a/figures/Fig1-designProcess/tune.pdf and b/figures/Fig1-designProcess/tune.pdf differ diff --git a/flexibleSubsetSelection/algorithm.py b/flexibleSubsetSelection/algorithm.py index 442096d..008b409 100644 --- a/flexibleSubsetSelection/algorithm.py +++ b/flexibleSubsetSelection/algorithm.py @@ -140,7 +140,7 @@ def worstOfRandom(dataset, lossFunction, subsetSize, minLoss=0, def greedySwap(dataset, lossFunction, subsetSize, minLoss=0, maxIterations=None, - seed=None): + seed=None, callback=None): """ A greedy algorithm with a greedy swap heuristic for subset selection. @@ -170,6 +170,9 @@ def greedySwap(dataset, lossFunction, subsetSize, minLoss=0, maxIterations=None, for i in range(maxIterations): log.debug("Iteration %s/%s: Loss %s.", i, maxIterations, loss) + if callback: + callback(iterations, loss) + if i not in indices: zSwapBest = np.copy(z) lossSwapBest = loss @@ -199,7 +202,7 @@ def greedySwap(dataset, lossFunction, subsetSize, minLoss=0, maxIterations=None, return z, loss # return indicator and final loss def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, - maxIterations=None, seed=None, initialSize=1): + maxIterations=None, seed=None, initialSize=1, callback=None): """ A greedy algorithm for subset selection to minimize the size of the subset such that lossFunction(subset) <= epsilon. @@ -214,6 +217,7 @@ def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, seed (int, rng, optional): The random seed or NumPy rng for random generation and reproducibility initialSize (int, optional): Initial size of the subset + callback (function, optional): A callback function for loss values Returns: z (array): Indicator vector of included items in the subset @@ -252,6 +256,8 @@ def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, while iterations < maxIterations: log.debug("Iteration: %s, Loss: %s, Error: %s, Subset Size: %s.", iterations, current_loss, error, np.sum(z)) + if callback: + callback(iterations, current_loss, subsetSize=np.sum(z)) # Check if error is less than or equal to epsilon if error <= epsilon: @@ -314,7 +320,7 @@ def greedyMinSubset(dataset, lossFunction, epsilon, minError=0, return z, error def greedyMixed(dataset, lossFunction, weight=1.0, minError=0, - maxIterations=None, seed=None, initialSize=1): + maxIterations=None, seed=None, initialSize=1, callback=None): """ A greedy algorithm to minimize the total loss = weight * subsetSize + lossFunction.calculate(). @@ -363,6 +369,8 @@ def greedyMixed(dataset, lossFunction, weight=1.0, minError=0, while iterations < maxIterations: log.debug("Iteration %s: Total Loss %s, Subset Size %s", iterations, total_loss, np.sum(z)) + if callback: + callback(iterations, total_loss, subsetSize=np.sum(z)) # Check if error is less than or equal to minError if error <= minError: diff --git a/flexibleSubsetSelection/plot.py b/flexibleSubsetSelection/plot.py index a545fd4..30eb8e1 100644 --- a/flexibleSubsetSelection/plot.py +++ b/flexibleSubsetSelection/plot.py @@ -4,6 +4,8 @@ from typing import Callable # Third party +from IPython.display import display, clear_output + import matplotlib from matplotlib.axes import Axes from matplotlib.colors import to_rgb, to_hex @@ -346,4 +348,58 @@ def histogram(ax: Axes, color: Color, dataset: (Dataset | None) = None, positions = barPositions[i] + np.arange(numBins) ax.bar(positions, subsetHeights, width=1, - color=color.palette["darkGreen"], alpha=0.5) \ No newline at end of file + color=color.palette["darkGreen"], alpha=0.5) + +class RealTimePlotter: + def __init__(self, color): + # Initialize the figure and axis + self.fig, self.ax = plt.subplots(figsize=(4, 4)) + self.iterations = [] + self.losses = [] + self.subsetSizes = [] + self.color = color + + # Set up the initial plot + self.ax.set_xlabel('Iteration') + self.ax.set_ylabel('Loss') + self.ax.set_title('Real-Time Loss During Solver') + self.ax.set_ylim(bottom=0) # Set the lower y-axis limit to 0 + + # Display the figure initially + display(self.fig) + + def update(self, iteration, loss, subsetSize=None): + # Append the current iteration and loss to lists + self.iterations.append(iteration) + self.losses.append(loss) + self.subsetSizes.append(subsetSize) + + # Clear the previous output (but don't clear the figure) + clear_output(wait=True) + self.ax.clear() + + self.ax.set_xlabel('Iteration') + # self.ax.set_ylabel('Loss') + self.ax.set_title('Minimum Loss') + + # Plot the updated loss values + self.ax.plot(self.iterations, + self.losses, + c=self.color["orange"], + label="Loss", + lw=2) + if subsetSize is not None: + self.ax.plot(self.iterations, + self.subsetSizes, + c=self.color["green"], + label="Subset Size", + lw=2) + self.ax.legend() + + # Display the updated plot + display(self.fig) + plt.close(self.fig) + + def close(self): + # Close the plot when done + plt.close(self.fig) \ No newline at end of file diff --git a/jupyter/Fig1-designProcess.ipynb b/jupyter/Fig1-designProcess.ipynb index 4b11961..6d4bffc 100644 --- a/jupyter/Fig1-designProcess.ipynb +++ b/jupyter/Fig1-designProcess.ipynb @@ -13,17 +13,15 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - "\n", - "\n", - "\n" + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" ] } ], @@ -33,6 +31,8 @@ "from pathlib import Path\n", "\n", "# Third party\n", + "from IPython.display import clear_output, display\n", + "\n", "import matplotlib.pyplot as plt\n", "import matplotlib_inline\n", "\n", @@ -45,6 +45,7 @@ "# Initialize notebook settings\n", "sns.set_theme() # set seaborn theme\n", "matplotlib_inline.backend_inline.set_matplotlib_formats('svg') # vector plots\n", + "%matplotlib inline\n", "%load_ext autoreload\n", "%autoreload 2" ] @@ -60,23 +61,13 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 114, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "2024-10-10 13:12:15,752 - flexibleSubsetSelection.sets - INFO: Dataset with 200 rows and 2 features: [0, 1] created.\n", - "2024-10-10 13:12:15,753 - flexibleSubsetSelection.sets - INFO: Data successfully saved at '../data/Fig1-designProcess/fullData.pickle'.\n" - ] - } - ], + "outputs": [], "source": [ - "directory = \"Fig1-designProcess\" # data directory for this notebook\n", - "seed = 123456789 # random seed for replicability\n", - "fss.logger.setup(level = logging.DEBUG) # set logging level for the package\n", + "directory = \"Fig1-designProcess\" # data directory for this notebook\n", + "seed = 123456789 # random seed for replicability\n", + "fss.logger.setup(level = logging.WARNING) # set logging level for the package\n", "\n", "# Create a random blobs dataset to use as our example dataset\n", "dataset = fss.Dataset(randTypes=\"blobs\", size=(200, 2), seed=seed)\n", @@ -99,146 +90,7 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2024-10-10 13:12:19,144 - flexibleSubsetSelection.sets - INFO: Data preprocessed with function 'hull'.\n", - "2024-10-10 13:12:19,145 - flexibleSubsetSelection.loss - INFO: Initialized a uni-criterion loss function with objective: preserveMetric, solve array: dataArray, selection method: row, and parameters: {'metric': , 'datasetMetric': 48.93447555042436}\n", - "2024-10-10 13:12:19,146 - flexibleSubsetSelection.solver - DEBUG: Initializing Solver with algorithm: greedyMinSubset, lossFunction: Uni-criterion: preserveMetric, hull, savePath: ../data/solverData.csv\n", - "2024-10-10 13:12:19,146 - flexibleSubsetSelection.solver - DEBUG: Log file already exists at ../data/solverData.csv\n", - "2024-10-10 13:12:19,147 - flexibleSubsetSelection.solver - INFO: Initialized a 'greedyMinSubset' solver.\n", - "2024-10-10 13:12:19,147 - flexibleSubsetSelection.algorithm - DEBUG: Solving for a subset such that loss(subset) <= 0.\n", - "2024-10-10 13:12:19,149 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 0, Loss: 42.23945382223514, Error: 42.23945382223514, Subset Size: 3.\n", - "2024-10-10 13:12:19,171 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 1, Loss: 23.054327728930527, Error: 23.054327728930527, Subset Size: 4.\n", - "2024-10-10 13:12:19,191 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 2, Loss: 11.133231203775615, Error: 11.133231203775615, Subset Size: 5.\n", - "2024-10-10 13:12:19,210 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 3, Loss: 1.8340851157977838, Error: 1.8340851157977838, Subset Size: 6.\n", - "2024-10-10 13:12:19,232 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 4, Loss: 0.7160766035798432, Error: 0.7160766035798432, Subset Size: 7.\n", - "2024-10-10 13:12:19,252 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 5, Loss: 0.013246909388804795, Error: 0.013246909388804795, Subset Size: 8.\n", - "2024-10-10 13:12:19,274 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 6, Loss: 1.6379421907686265e-06, Error: 1.6379421907686265e-06, Subset Size: 9.\n", - "2024-10-10 13:12:19,295 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 7, Loss: 0.0, Error: 0.0, Subset Size: 10.\n", - "2024-10-10 13:12:19,296 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 7, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,317 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 8, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,338 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 9, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,361 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 10, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,381 - flexibleSubsetSelection.algorithm - DEBUG: Iteration: 11, Loss: 0.0, Error: 0.0, Subset Size: 7.\n", - "2024-10-10 13:12:19,382 - flexibleSubsetSelection.solver - INFO: Selected subset with 'greedyMinSubset' and 'Uni-criterion: preserveMetric, hull' in 0.23s with 0.0 loss.\n", - "2024-10-10 13:12:19,383 - flexibleSubsetSelection.sets - INFO: Created subset of size 7x2 in 0.23s with 0.0 loss.\n", - "2024-10-10 13:12:19,384 - flexibleSubsetSelection.solver - INFO: Saved solver performance data to ../data/solverData.csv.\n", - "2024-10-10 13:12:19,385 - flexibleSubsetSelection.sets - INFO: Data successfully saved at '../data/Fig1-designProcess/hullSubset.pickle'.\n" - ] - } - ], - "source": [ - "# Precalculate the hull metric on the full dataset\n", - "dataset.preprocess(hull = fss.metric.hull)\n", - "\n", - "# Create a unicriterion loss function with the hull metric and precomputation\n", - "lossFunction = fss.UniCriterion(objective = fss.objective.preserveMetric, \n", - " metric = fss.metric.hull,\n", - " datasetMetric = dataset.hull)\n", - "\n", - "# Create a solve method with a greedy algorithm and a set subset size\n", - "solver = fss.Solver(algorithm = fss.algorithm.greedyMinSubset, \n", - " lossFunction = lossFunction)\n", - "\n", - "# Solve for a convex hull subset\n", - "subsetHull = solver.solve(dataset, epsilon=0, initialSize=3)\n", - "subsetHull.save(f\"{directory}/hullSubset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Outliers Objective\n", - "\n", - "Applying this objective allows us to select a subset of 40 points with the highest local outlier effect.\n", - "\n", - "\\begin{align*}\n", - "\\max_{S \\in \\mathbb{S}} & \\quad \\text{LOF}(S) \\\\\n", - "\\text{s.t.} & \\quad \\|S\\| = 40\n", - "\\end{align*}" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2024-10-10 13:10:40,381 - flexibleSubsetSelection.sets - INFO: Data preprocessed with function 'outlierness'.\n", - "2024-10-10 13:10:40,381 - flexibleSubsetSelection.loss - INFO: Initialized a uni-criterion loss function with objective: sum, solve array: outlierness, selection method: row, and parameters: {}\n", - "2024-10-10 13:10:40,417 - flexibleSubsetSelection.solver - INFO: Selected subset with 'greedySwap' and 'Uni-criterion: sum, outlierness' in 0.04s with -66.43006587269934 loss.\n", - "2024-10-10 13:10:40,418 - flexibleSubsetSelection.sets - INFO: Created subset of size 40x2 in 0.04s with -66.43 loss.\n", - "2024-10-10 13:10:40,419 - flexibleSubsetSelection.solver - INFO: Saved solver performance data to ../data/solverData.csv.\n", - "2024-10-10 13:10:40,421 - flexibleSubsetSelection.sets - INFO: Data successfully saved at '../data/Fig1-designProcess/outliersSubset.pickle'.\n" - ] - } - ], - "source": [ - "# Precalculate the outlierness (local outlier effect) of the full dataset\n", - "dataset.preprocess(outlierness = fss.objective.outlierness)\n", - "\n", - "# Create a loss function that is just the sum of the LOF in the subset\n", - "solver.lossFunction = fss.UniCriterion(objective = np.sum, \n", - " solveArray = \"outlierness\")\n", - "solver.algorithm = fss.algorithm.greedySwap\n", - "\n", - "# Solve for an outlier subset\n", - "subsetOutliers = solver.solve(dataset, subsetSize=40, maxIterations=100)\n", - "subsetOutliers.save(f\"{directory}/outliersSubset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Distinctness Objective\n", - "\n", - "Applying this objective allows us to select a subset of 60 points that are distant from their nearest neighbors in 2D space.\n", - "\n", - "\\begin{align*}\n", - "\\max_{S \\in \\mathbb{S}} & \\quad \\text{Distinctness}(S) \\\\\n", - "\\text{s.t.} & \\quad \\|S\\| = 60\n", - "\\end{align*}" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a unicriterion loss function with the distinctness objective\n", - "dataset.preprocess(distances = fss.metric.distanceMatrix)\n", - "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", - " solveArray = \"distances\",\n", - " selectBy = \"matrix\")\n", - "\n", - "# Solve for distinctness subset\n", - "subsetDistinct = solver.solve(dataset=dataset, subsetSize=60)\n", - "subsetDistinct.save(f\"{directory}/distinctSubset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot\n", - "\n", - "Now we visualize these three example objectives by plotting the dataset and subsets in 3 scatterplots." - ] - }, - { - "cell_type": "code", - "execution_count": 10, + "execution_count": 115, "metadata": {}, "outputs": [ { @@ -247,12 +99,12 @@ "\n", "\n", - "\n", + "\n", " \n", " \n", " \n", " \n", - " 2024-10-10T12:40:59.708896\n", + " 2024-10-11T15:31:57.532307\n", " image/svg+xml\n", " \n", " \n", @@ -267,604 +119,236 @@ " \n", " \n", " \n", - " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + "\" transform=\"scale(0.015625)\"/>\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", "\n" ], "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -1523,118 +970,49 @@ } ], "source": [ - "# Initialize color and plot settings\n", - "color = fss.Color()\n", - "fss.plot.initialize(color, font=\"DejaVu Sans\")\n", + "# Precalculate the hull metric on the full dataset\n", + "dataset.preprocess(hull = fss.metric.hull)\n", "\n", - "# Plot the three different resulting subsets as scatterplots\n", - "titleSize = 24\n", - "subtitleSize = 18\n", - "titles = [\"Hull\", \"Outliers\", \"Distinctness\"]\n", - "subsets = [subsetHull, subsetOutliers, subsetDistinct]\n", + "# Create a unicriterion loss function with the hull metric and precomputation\n", + "lossFunction = fss.UniCriterion(objective = fss.objective.preserveMetric, \n", + " metric = fss.metric.hull,\n", + " datasetMetric = dataset.hull)\n", "\n", - "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", - "fig.text(0.49, 1, '1. Express', ha='center', va='center', fontsize=titleSize)\n", + "# Create a solve method with a greedy algorithm and a set subset size\n", + "solver = fss.Solver(algorithm = fss.algorithm.greedyMinSubset, \n", + " lossFunction = lossFunction)\n", "\n", - "for i, ax in enumerate(fig.axes):\n", - " ax.grid(visible=False)\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " ax.set_title(titles[i], fontsize=subtitleSize)\n", - " # ax.set_aspect(\"equal\")\n", + "# Initialize color and plot settings\n", + "color = fss.Color()\n", + "fss.plot.initialize(color, font=\"DejaVu Sans\")\n", + "lossPlotter = fss.plot.RealTimePlotter(color)\n", "\n", - " fss.plot.scatter(ax = ax, \n", - " color = color, \n", - " dataset = dataset, \n", - " subset = subsets[i], \n", - " alpha = 0.6)\n", + "# Solve for a convex hull subset\n", + "subsetHull = solver.solve(dataset, \n", + " epsilon = 0, \n", + " initialSize = 3, \n", + " callback = lossPlotter.update)\n", "\n", - "plt.savefig(f\"../figures/{directory}/express.pdf\", bbox_inches=\"tight\")" + "subsetHull.save(f\"{directory}/hullSubset\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Blend\n", + "### Outliers Objective\n", "\n", - "For visualizations with multiple criteria, objectives can be combined together to achieve more complicated outcomes. Multiple criteria can be balanced using the weight parameters to ensure the objectives apply to the subsets at desirable levels. Here we create three different subsets that blend a distribution objective (using the earth movers distance as the metric) with the distinctness objective from the previous section. Each subset blends the two objectives differently by varying the weights.\n", + "Applying this objective allows us to select a subset of 40 points with the highest local outlier effect.\n", "\n", "\\begin{align*}\n", - "\\min_{S \\in \\mathbb{S}} & \\quad \\lambda_0 \\text{EMD}(S) + \\lambda_1 \\text{Distinctness}(S) \\\\\n", - "\\text{s.t.} & \\quad \\|S\\| = 80\n", + "\\max_{S \\in \\mathbb{S}} & \\quad \\text{LOF}(S) \\\\\n", + "\\text{s.t.} & \\quad \\|S\\| = 40\n", "\\end{align*}" ] }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "subsetSize = 80 # The size of subsets being selected with blended objectives\n", - "\n", - "# Use distribution and distinctness objectives\n", - "objectives = [fss.objective.earthMoversDistance, fss.objective.distinctness]\n", - "\n", - "# Parameters of the distribution and distinctness objectives\n", - "parameters = [{\"dataset\": dataset.dataArray}, \n", - " {\"solveArray\": \"distances\", \"selectBy\": \"matrix\"}]\n", - "\n", - "# Create the multicriterion loss function from the objectives and weight them\n", - "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", - " parameters = parameters, \n", - " weights=[100, 1])\n", - "\n", - "# Solve for the blended distribution and distinctness subset\n", - "subsetBlend1 = solver.solve(dataset, subsetSize=subsetSize)\n", - "subsetBlend1.save(f\"{directory}/blend1Subset\")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Update the weights to provide less emphasis on the distribution objective\n", - "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", - " parameters = parameters, \n", - " weights=[10, 1])\n", - "\n", - "# Solve for the blended distribution and distinctness subset\n", - "subsetBlend2 = solver.solve(dataset, subsetSize=subsetSize)\n", - "subsetBlend2.save(f\"{directory}/blend2Subset\")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Update the weights to an even weight of the two objectives\n", - "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", - " parameters = parameters, \n", - " weights=[1, 1])\n", - "\n", - "# Solve for the blended distribution and distinctness subset\n", - "subsetBlend3 = solver.solve(dataset, subsetSize=subsetSize)\n", - "subsetBlend3.save(f\"{directory}/blend3Subset\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot\n", - "\n", - "Now we visualize these three example blended subsets by plotting the dataset and subsets in 3 scatterplots." - ] - }, - { - "cell_type": "code", - "execution_count": 14, + "execution_count": 117, "metadata": {}, "outputs": [ { @@ -1643,12 +1021,12 @@ "\n", "\n", - "\n", + "\n", " \n", " \n", " \n", " \n", - " 2024-10-10T12:41:49.800928\n", + " 2024-10-11T15:35:55.117881\n", " image/svg+xml\n", " \n", " \n", @@ -1663,320 +1041,219 @@ " \n", " \n", " \n", - " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + "M 2034 4750 \n", + "Q 2819 4750 3233 4129 \n", + "Q 3647 3509 3647 2328 \n", + "Q 3647 1150 3233 529 \n", + "Q 2819 -91 2034 -91 \n", + "Q 1250 -91 836 529 \n", + "Q 422 1150 422 2328 \n", + "Q 422 3509 836 4129 \n", + "Q 1250 4750 2034 4750 \n", + "z\n", + "\" transform=\"scale(0.015625)\"/>\n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", + " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + "\" style=\"fill: #eff0f2; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter\"/>\n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Precalculate the outlierness (local outlier effect) of the full dataset\n", + "dataset.preprocess(outlierness = fss.objective.outlierness)\n", + "\n", + "# Create a loss function that is just the sum of the LOF in the subset\n", + "solver.lossFunction = fss.UniCriterion(objective = np.sum, \n", + " solveArray = \"outlierness\")\n", + "solver.algorithm = fss.algorithm.greedySwap\n", + "\n", + "# Solve for an outlier subset\n", + "subsetOutliers = solver.solve(dataset, \n", + " subsetSize = 40, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "\n", + "subsetOutliers.save(f\"{directory}/outliersSubset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Distinctness Objective\n", + "\n", + "Applying this objective allows us to select a subset of 60 points that are distant from their nearest neighbors in 2D space.\n", + "\n", + "\\begin{align*}\n", + "\\max_{S \\in \\mathbb{S}} & \\quad \\text{Distinctness}(S) \\\\\n", + "\\text{s.t.} & \\quad \\|S\\| = 60\n", + "\\end{align*}" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:37:26.487257\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a unicriterion loss function with the distinctness objective\n", + "dataset.preprocess(distances = fss.metric.distanceMatrix)\n", + "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", + " solveArray = \"distances\",\n", + " selectBy = \"matrix\")\n", + "\n", + "# Solve for distinctness subset\n", + "subsetDistinct = solver.solve(dataset=dataset, \n", + " subsetSize=60, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetDistinct.save(f\"{directory}/distinctSubset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot\n", + "\n", + "Now we visualize these three example objectives by plotting the dataset and subsets in 3 scatterplots." + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:37:50.365496\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the three different resulting subsets as scatterplots\n", + "titleSize = 24\n", + "subtitleSize = 18\n", + "titles = [\"Hull\", \"Outliers\", \"Distinctness\"]\n", + "subsets = [subsetHull, subsetOutliers, subsetDistinct]\n", + "\n", + "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", + "fig.text(0.49, 1, '1. Express', ha='center', va='center', fontsize=titleSize)\n", + "\n", + "for i, ax in enumerate(fig.axes):\n", + " ax.grid(visible=False)\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax.set_title(titles[i], fontsize=subtitleSize)\n", + " # ax.set_aspect(\"equal\")\n", + "\n", + " fss.plot.scatter(ax = ax, \n", + " color = color, \n", + " dataset = dataset, \n", + " subset = subsets[i], \n", + " alpha = 0.6)\n", + "\n", + "plt.savefig(f\"../figures/{directory}/express.pdf\", bbox_inches=\"tight\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Blend\n", + "\n", + "For visualizations with multiple criteria, objectives can be combined together to achieve more complicated outcomes. Multiple criteria can be balanced using the weight parameters to ensure the objectives apply to the subsets at desirable levels. Here we create three different subsets that blend a distribution objective (using the earth movers distance as the metric) with the distinctness objective from the previous section. Each subset blends the two objectives differently by varying the weights.\n", + "\n", + "\\begin{align*}\n", + "\\min_{S \\in \\mathbb{S}} & \\quad \\lambda_0 \\text{EMD}(S) + \\lambda_1 \\text{Distinctness}(S) \\\\\n", + "\\text{s.t.} & \\quad \\|S\\| = 80\n", + "\\end{align*}" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:39:35.141220\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "subsetSize = 80 # The size of subsets being selected with blended objectives\n", + "\n", + "# Use distribution and distinctness objectives\n", + "objectives = [fss.objective.earthMoversDistance, fss.objective.distinctness]\n", + "\n", + "# Parameters of the distribution and distinctness objectives\n", + "parameters = [{\"dataset\": dataset.dataArray}, \n", + " {\"solveArray\": \"distances\", \"selectBy\": \"matrix\"}]\n", + "\n", + "# Create the multicriterion loss function from the objectives and weight them\n", + "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", + " parameters = parameters, \n", + " weights=[100, 1])\n", + "\n", + "# Solve for the blended distribution and distinctness subset\n", + "subsetBlend1 = solver.solve(dataset, \n", + " subsetSize=subsetSize, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetBlend1.save(f\"{directory}/blend1Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:41:07.736944\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Update the weights to provide less emphasis on the distribution objective\n", + "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", + " parameters = parameters, \n", + " weights=[10, 1])\n", + "\n", + "# Solve for the blended distribution and distinctness subset\n", + "subsetBlend2 = solver.solve(dataset, \n", + " subsetSize=subsetSize, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetBlend2.save(f\"{directory}/blend2Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:42:16.644960\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Update the weights to an even weight of the two objectives\n", + "solver.lossFunction = fss.MultiCriterion(objectives = objectives, \n", + " parameters = parameters, \n", + " weights=[1, 1])\n", + "\n", + "# Solve for the blended distribution and distinctness subset\n", + "subsetBlend3 = solver.solve(dataset, \n", + " subsetSize=subsetSize, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetBlend3.save(f\"{directory}/blend3Subset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot\n", + "\n", + "Now we visualize these three example blended subsets by plotting the dataset and subsets in 3 scatterplots." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-10T13:23:57.066961\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the three subsets with different blends of the two objectives\n", + "titles = [\"More Distribution,\\nLess Distinct\", \"\", \n", + " \"Less Distribution,\\nMore Distinct\"]\n", + "subsets = [subsetBlend1, subsetBlend2, subsetBlend3]\n", + "\n", + "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", + "fig.text(0.49, 1, '2. Blend', ha='center', va='center', fontsize=titleSize)\n", + "\n", + "for i, ax in enumerate(fig.axes):\n", + " ax.grid(visible=False)\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax.set_title(titles[i], fontsize=subtitleSize)\n", + "\n", + " fss.plot.scatter(ax = ax, \n", + " color = color,\n", + " dataset = dataset,\n", + " subset = subsets[i],\n", + " alpha = 0.6)\n", + "\n", + "plt.savefig(f\"../figures/{directory}/blend.pdf\", bbox_inches=\"tight\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tune\n", + "\n", + "Along with the weight parameters that help in blending objectives, the parameters of the objectives and the optimization formulation can be tuned to select a subset that is more effective for a given visualization. For example, the subset size, loss bounds, and subset weight parameters can be used to tune the subset size for a particular visualization. Objectives may have parameters associated with them such as the number of clusters in a clustering objective, the amount of seperation in a distinctness objective, or the smoothing parameter of a kernel density estimation. These provide additional flexibility to tune the objectives to a desirable level. Here we tune the subset size by varying the weight given to this fundamental characteristic of a subset to three different levels. \n", + "\n", + "$$\\min_{S \\in \\mathbb{S}} \\space \\lambda \\|S\\| + \\text{Distinctness}(S)$$" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:46:53.637614\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a unicriterion loss function with the distinctness objective\n", + "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", + " solveArray = \"distances\",\n", + " selectBy = \"matrix\")\n", + "solver.algorithm = fss.algorithm.greedyMixed\n", + "\n", + "# Solve for subsets with 3 different subset sizes\n", + "subsetDistinct1 = solver.solve(dataset=dataset, weight=0.5, initialSize=3, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetDistinct1.save(f\"{directory}/distinct1Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:47:08.133220\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ], + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "subsetDistinct2 = solver.solve(dataset=dataset, weight=0.25, initialSize=3, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", + "subsetDistinct2.save(f\"{directory}/distinct2Subset\")" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2024-10-11T15:47:24.868033\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.9.2, https://matplotlib.org/\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", + " \n", + " \n", + " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", "\n" ], "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -3142,60 +11274,9 @@ } ], "source": [ - "# Plot the three subsets with different blends of the two objectives\n", - "titles = [\"More Distribution,\\nLess Distinct\", \"\", \n", - " \"Less Distribution,\\nMore Distinct\"]\n", - "subsets = [subsetBlend1, subsetBlend2, subsetBlend3]\n", - "\n", - "fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(8, 3.5))\n", - "fig.text(0.49, 1, '2. Blend', ha='center', va='center', fontsize=titleSize)\n", - "\n", - "for i, ax in enumerate(fig.axes):\n", - " ax.grid(visible=False)\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " ax.set_title(titles[i], fontsize=subtitleSize)\n", - "\n", - " fss.plot.scatter(ax = ax, \n", - " color = color,\n", - " dataset = dataset,\n", - " subset = subsets[i],\n", - " alpha = 0.6)\n", - "\n", - "plt.savefig(f\"../figures/{directory}/blend.pdf\", bbox_inches=\"tight\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tune\n", - "\n", - "Along with the weight parameters that help in blending objectives, the parameters of the objectives and the optimization formulation can be tuned to select a subset that is more effective for a given visualization. For example, the subset size, loss bounds, and subset weight parameters can be used to tune the subset size for a particular visualization. Objectives may have parameters associated with them such as the number of clusters in a clustering objective, the amount of seperation in a distinctness objective, or the smoothing parameter of a kernel density estimation. These provide additional flexibility to tune the objectives to a desirable level. Here we tune the subset size by varying the weight given to this fundamental characteristic of a subset to three different levels. \n", - "\n", - "$$\\min_{S \\in \\mathbb{S}} \\space \\lambda \\|S\\| + \\text{Distinctness}(S)$$" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a unicriterion loss function with the distinctness objective\n", - "solver.lossFunction = fss.UniCriterion(objective = fss.objective.distinctness,\n", - " solveArray = \"distances\",\n", - " selectBy = \"matrix\")\n", - "solver.algorithm = fss.algorithm.greedyMixed\n", "\n", - "# Solve for subsets with 3 different subset sizes\n", - "subsetDistinct1 = solver.solve(dataset=dataset, weight=0.5, initialSize=3)\n", - "subsetDistinct1.save(f\"{directory}/distinct1Subset\")\n", - "\n", - "subsetDistinct2 = solver.solve(dataset=dataset, weight=0.25, initialSize=3)\n", - "subsetDistinct2.save(f\"{directory}/distinct2Subset\")\n", - "\n", - "subsetDistinct3 = solver.solve(dataset=dataset, weight=0.05, initialSize=3)\n", + "subsetDistinct3 = solver.solve(dataset=dataset, weight=0.05, initialSize=3, \n", + " callback = fss.plot.RealTimePlotter(color).update)\n", "subsetDistinct3.save(f\"{directory}/distinct3Subset\")" ] }, @@ -3210,7 +11291,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -3224,7 +11305,7 @@ " \n", " \n", " \n", - " 2024-10-10T12:41:50.823898\n", + " 2024-10-10T13:23:58.321458\n", " image/svg+xml\n", " \n", " \n", @@ -3279,7 +11360,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -3797,7 +11878,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -3865,245 +11947,229 @@ "\" style=\"fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4139,207 +12205,207 @@ "\" style=\"fill: none; stroke: #ffffff; stroke-width: 1.25; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4387,51 +12453,99 @@ " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4523,13 +12637,13 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n",