Skip to content

Commit

Permalink
Minor class reorganization.
Browse files Browse the repository at this point in the history
  • Loading branch information
cbbcbail committed Aug 1, 2024
1 parent b0811f5 commit 1b1cb0c
Show file tree
Hide file tree
Showing 17 changed files with 108 additions and 100 deletions.
Binary file modified data/Fig1-designProcess/blend1Subset.pickle
Binary file not shown.
Binary file modified data/Fig1-designProcess/distinctSubset.pickle
Binary file not shown.
Binary file modified data/Fig1-designProcess/fullData.pickle
Binary file not shown.
Binary file modified data/Fig1-designProcess/hullSubset.pickle
Binary file not shown.
Binary file modified data/Fig1-designProcess/outliersSubset.pickle
Binary file not shown.
4 changes: 4 additions & 0 deletions data/solverLog.csv
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,7 @@ Uni-criterion: clusterCenters,greedySwap,1000,2,10,0.13824820891022682,0.7651631
"Uni-criterion: distinctness, distances",greedyMixed,200,2,27,0.12416926166042686,-41.35106343740662
"Uni-criterion: distinctness, distances",greedyMixed,200,2,14,0.0512898382730782,-42.63467324402975
"Uni-criterion: distinctness, distances",greedyMixed,200,2,91,0.3911852678284049,-69.8726033176274
"Uni-criterion: preserveMetric, hull",greedyMinSubset,200,2,12,0.10196879226714373,0.0
"Uni-criterion: sum, outlierness",greedySwap,200,2,40,0.02950233267620206,-83.70271953374831
"Uni-criterion: distinctness, distances",greedySwap,200,2,60,0.1577538326382637,-74.06808510204883
"Multi-criterion: 100*(earthMoversDistance) + 1*(distinctness, distances)",greedySwap,200,2,80,8.527639084029943,-38.28864852224051
Binary file modified figures/Fig1-designProcess/express.pdf
Binary file not shown.
1 change: 1 addition & 0 deletions flexibleSubsetSelection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .sets import Dataset, Subset # Data management classes
from .loss import UniCriterion, MultiCriterion # Loss function classes
from .solver import Solver # Solver class
from .color import Color # Color class

# Import sub-level component functions
from . import (
Expand Down
73 changes: 73 additions & 0 deletions flexibleSubsetSelection/color.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# --- Imports ------------------------------------------------------------------

# Third party
import seaborn as sns


# --- Color --------------------------------------------------------------------

class Color:
"""
Create and store color palettes and color bars for use in visualizations
"""
def __init__(self, palette: dict | None = None):
"""
Initialize the class with a custom or default palette
Args:
palette: dictionary of color names and color values
"""
if palette is None:
self.palette = {
"green": "#8dd3c7",
"darkGreen": "#338477",
"orange": "#fb8072",
"yellow": "#fdb462",
"blue": "#8dadd3",
"grey": "#eff0f2"
}
else:
self.palette = palette

def __getitem__(self, color):
"""Returns a color value from the palette directly."""
return self.palette[color]

def getPalette(self, names: list, colors: list) -> dict:
"""
Create a custom palette for a categorical set by assigning colors from
the default set to a category name.
Args:
names: List of category names to assign a color to
colors: corresponding colors to assign to the names
Returns: dictionary of names and colors
Raises: ValueError if the names and color lists do not match
"""

if len(names) != len(colors):
raise ValueError("Names and colors lists must be the same length.")

return {name: self.palette[color] for name, color in zip(names, colors)}

def getGradientPalette(self, color: str, number: int = 6,
type: str = "light") -> list:
"""
Create a gradient palette based on a base color.
Args:
color: The base color to create a gradient from.
number: Number of colors in the gradient palette.
Returns: A list of colors in the gradient palette.
Raises: ValueError if type is not light or dark.
"""
if type == "light":
return sns.light_palette(color=self.palette[color], n_colors=number)
elif type == "dark":
return sns.dark_palette(color=self.palette[color], n_colors=number)
else:
raise ValueError("Palette type unrecognized.")
6 changes: 3 additions & 3 deletions flexibleSubsetSelection/loss.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from numpy.typing import ArrayLike

# Local files
from . import sets
from .sets import Dataset, Subset


# --- Loss Function ------------------------------------------------------------
Expand Down Expand Up @@ -51,7 +51,7 @@ def __init__(self, objectives: List[Callable],
# Generate the combined objective function
self.calculate = partial(self._loss)

def _loss(self, dataset: sets.Dataset, z: ArrayLike) -> float:
def _loss(self, dataset: Dataset, z: ArrayLike) -> float:
"""
Compute the overall loss function by evaluating each objective function
with its corresponding parameters and combining them with weights.
Expand Down Expand Up @@ -131,7 +131,7 @@ def __init__(self, objective: Callable, solveArray: str = "dataArray",
self.selectBy = selectBy
self.parameters = parameters

def calculate(self, dataset: sets.Dataset, z: ArrayLike) -> float:
def calculate(self, dataset: Dataset, z: ArrayLike) -> float:
"""
Compute the loss by evaluating the objective with its parameters on the
selected subset.
Expand Down
83 changes: 8 additions & 75 deletions flexibleSubsetSelection/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,75 +15,8 @@
import seaborn as sns

# Local files
from . import sets

# --- Color --------------------------------------------------------------------

class Color:
"""
Create and store color palettes and color bars for use in visualizations
"""
def __init__(self, palette: dict | None = None):
"""
Initialize the class with a custom or default palette
Args:
palette: dictionary of color names and color values
"""
if palette is None:
self.palette = {
"green": "#8dd3c7",
"darkGreen": "#338477",
"orange": "#fb8072",
"yellow": "#fdb462",
"blue": "#8dadd3",
"grey": "#eff0f2"
}
else:
self.palette = palette

def __getitem__(self, color):
"""Returns a color value from the palette directly."""
return self.palette[color]

def getPalette(self, names: list, colors: list) -> dict:
"""
Create a custom palette for a categorical set by assigning colors from
the default set to a category name.
Args:
names: List of category names to assign a color to
colors: corresponding colors to assign to the names
Returns: dictionary of names and colors
Raises: ValueError if the names and color lists do not match
"""

if len(names) != len(colors):
raise ValueError("Names and colors lists must be the same length.")

return {name: self.palette[color] for name, color in zip(names, colors)}

def getGradientPalette(self, color: str, number: int = 6,
type: str = "light") -> list:
"""
Create a gradient palette based on a base color.
Args:
color: The base color to create a gradient from.
number: Number of colors in the gradient palette.
Returns: A list of colors in the gradient palette.
Raises: ValueError if type is not light or dark.
"""
if type == "light":
return sns.light_palette(color=self.palette[color], n_colors=number)
elif type == "dark":
return sns.dark_palette(color=self.palette[color], n_colors=number)
else:
raise ValueError("Palette type unrecognized.")
from .sets import Dataset, Subset
from .color import Color


# --- Figures ------------------------------------------------------------------
Expand Down Expand Up @@ -260,8 +193,8 @@ def initialize(color, font: str = "Times New Roman", size: int = 42,
else:
plt.rcParams["axes.facecolor"] = faceColorAx

def scatter(ax: Axes, color: Color, dataset: (sets.Dataset | None) = None,
subset: (sets.Subset | None) = None, features: (list | None) = None,
def scatter(ax: Axes, color: Color, dataset: (Dataset | None) = None,
subset: (Subset | None) = None, features: (list | None) = None,
**parameters) -> None:
"""
Plot a scatterplot of data features on ax
Expand Down Expand Up @@ -317,8 +250,8 @@ def scatter(ax: Axes, color: Color, dataset: (sets.Dataset | None) = None,
**parameters)

def parallelCoordinates(ax: Axes, color: Color,
dataset: (sets.Dataset | None) = None,
subset: (sets.Subset | None) = None,
dataset: (Dataset | None) = None,
subset: (Subset | None) = None,
dataLinewidth: float = 0.5,
subsetLinewidth: float = 1.5, **parameters) -> None:
"""
Expand Down Expand Up @@ -357,8 +290,8 @@ def parallelCoordinates(ax: Axes, color: Color,
alpha=1,
**parameters)

def histogram(ax: Axes, color: Color, dataset: (sets.Dataset | None) = None,
subset: (sets.Subset | None) = None, numBins: int = 6,
def histogram(ax: Axes, color: Color, dataset: (Dataset | None) = None,
subset: (Subset | None) = None, numBins: int = 6,
**parameters) -> None:
"""
Plot histograms of each feature side by side on ax with normalized subset
Expand Down
9 changes: 5 additions & 4 deletions flexibleSubsetSelection/sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

# --- Dataset and Subset Classes -----------------------------------------------

class Base:
class Set:
"""
Base class for Dataset and Subset providing shared save and load functions.
"""
Expand Down Expand Up @@ -81,7 +81,7 @@ def load(self, name: str, fileType: str = 'pickle',
print(f"Error loading file: {e}")


class Dataset(Base):
class Dataset(Set):
"""
A class for creating, storing, and processing of datasets for subsetting
"""
Expand Down Expand Up @@ -188,7 +188,8 @@ def scale(self, interval: (tuple | None) = None) -> None:
self.dataArray = self.dataArray * (interval[1] - interval[0])
self.dataArray += interval[0]

def discretize(self, bins: int | ArrayLike, features: (list | None) = None,
def discretize(self, bins: (int | ArrayLike),
features: (list | None) = None,
strategy: Literal["uniform","quantile","kmeans"] = "uniform",
array: (str | None) = None) -> None:
"""
Expand Down Expand Up @@ -267,7 +268,7 @@ def __str__(self) -> str:
return (f"Dataset with {self.size[0]} rows and {len(self.features)} "
f"features: {self.features}")

class Subset(Base):
class Subset(Set):
"""
A class for creating, storing, and handling subsets of datasets.
"""
Expand Down
14 changes: 6 additions & 8 deletions flexibleSubsetSelection/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import gurobipy as gp

# Local files
from . import loss
from . import sets
from .loss import UniCriterion, MultiCriterion
from .sets import Dataset, Subset
from .timer import Timer


Expand All @@ -21,9 +21,7 @@ class Solver():
solving algorithm and loss function, applied to calculate a subset.
"""
def __init__(self, algorithm: Callable,
lossFunction: (loss.UniCriterion |
loss.MultiCriterion |
None) = None,
lossFunction: (UniCriterion | MultiCriterion | None) = None,
logPath: str = "../data/solverLog.csv") -> None:
"""
Initialize a subset selection solver with a solve algorithm and,
Expand All @@ -48,7 +46,7 @@ def __init__(self, algorithm: Callable,
except FileExistsError:
pass

def solve(self, dataset: sets.Dataset, **parameters) -> sets.Subset:
def solve(self, dataset: Dataset, **parameters) -> Subset:
"""
Solve for the optimal subset with the algorithm and loss function for
the specified dataset.
Expand All @@ -62,7 +60,7 @@ def solve(self, dataset: sets.Dataset, **parameters) -> sets.Subset:
with Timer() as timer:
z, loss = self.algorithm(dataset, self.lossFunction, **parameters)

subset = sets.Subset(dataset, z, timer.elapsedTime, loss)
subset = Subset(dataset, z, timer.elapsedTime, loss)

self.log(dataset.size, subset.size, self.lossFunction,
self.algorithm.__name__, timer.elapsedTime, loss)
Expand All @@ -72,7 +70,7 @@ def solve(self, dataset: sets.Dataset, **parameters) -> sets.Subset:
return subset

def log(self, datasetSize: tuple, subsetSize: tuple,
lossFunction: loss.UniCriterion | loss.MultiCriterion,
lossFunction: (UniCriterion | MultiCriterion),
algorithm: str, computationTime: float, loss: float):

# Write log entry to the log file
Expand Down
12 changes: 5 additions & 7 deletions jupyter/Fig1-designProcess.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@
"outputs": [],
"source": [
"# Initialize color and plot settings\n",
"color = fss.plot.Color()\n",
"color = fss.Color()\n",
"fss.plot.initialize(color, font=\"DejaVu Sans\")\n",
"\n",
"# Plot the three different resulting subsets as scatterplots\n",
Expand Down Expand Up @@ -306,13 +306,12 @@
" 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",
" 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\")"
]
Expand Down Expand Up @@ -387,7 +386,6 @@
" 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",
Expand Down
2 changes: 1 addition & 1 deletion jupyter/Fig2&3-objectives.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
"outputs": [],
"source": [
"# Initialize color and plot settings\n",
"color = fss.plot.Color()\n",
"color = fss.Color()\n",
"fss.plot.initialize(color, font=\"DejaVu Sans\")\n",
"\n",
"nrows = 6\n",
Expand Down
2 changes: 1 addition & 1 deletion jupyter/Fig4-performance.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
"outputs": [],
"source": [
"# Initialize color and plot settings\n",
"color = fss.plot.Color()\n",
"color = fss.Color()\n",
"fss.plot.initialize(color)\n",
"\n",
"# Create figure\n",
Expand Down
2 changes: 1 addition & 1 deletion jupyter/Fig5-scatterplotOverdraw.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"outputs": [],
"source": [
"# Initialize color and plot settings\n",
"color = fss.plot.Color()\n",
"color = fss.Color()\n",
"fss.plot.initialize(color)\n",
"\n",
"# Create a color palette for categories of chess openings\n",
Expand Down

0 comments on commit 1b1cb0c

Please sign in to comment.