Skip to content

Commit b7c0d30

Browse files
0.28.4
contour updated
1 parent 7d71828 commit b7c0d30

3 files changed

Lines changed: 266 additions & 42 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
77

88
[project]
99
name = "spotpython"
10-
version = "0.28.3"
10+
version = "0.28.4"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotpython/plot/contour.py

Lines changed: 264 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ def plotCombinations(
517517
return None
518518

519519

520-
def create_contour_plot(data, x_col, y_col, z_col, facet_col=None, aspect=1, as_table=True, figsize=(3, 3), levels=5, cmap="viridis"):
520+
def create_contour_plot(data, x_col, y_col, z_col, facet_col=None, aspect=1, as_table=True, figsize=(3, 3), levels=5, cmap="viridis") -> None:
521521
"""
522522
Creates contour plots similar to R's contourplot function using matplotlib.
523523
@@ -611,7 +611,7 @@ def create_contour_plot(data, x_col, y_col, z_col, facet_col=None, aspect=1, as_
611611
# Set labels and title
612612
ax.set_xlabel(x_col)
613613
ax.set_ylabel(y_col)
614-
ax.set_title(f"{facet_col} = {np.round(facet_value,2)}")
614+
ax.set_title(f"{facet_col} = {np.round(facet_value, 2)}")
615615
ax.set_aspect(aspect)
616616

617617
# Remove empty subplots
@@ -630,7 +630,7 @@ def create_contour_plot(data, x_col, y_col, z_col, facet_col=None, aspect=1, as_
630630

631631
# Plot contour
632632
fig, ax = plt.subplots(figsize=figsize)
633-
contour = ax.contour(X, Y, Z, levels=10, cmap="viridis") # Adjust levels and cmap as needed
633+
contour = ax.contour(X, Y, Z, levels=levels, cmap="viridis") # Adjust levels and cmap as needed
634634
ax.clabel(contour, inline=True, fontsize=8)
635635

636636
# Set labels and title
@@ -642,7 +642,7 @@ def create_contour_plot(data, x_col, y_col, z_col, facet_col=None, aspect=1, as_
642642
plt.show()
643643

644644

645-
def mo_generate_plot_grid(variables, resolutions, functions):
645+
def mo_generate_plot_grid(variables, resolutions, functions) -> pd.DataFrame:
646646
"""
647647
Generate a grid of input variables and apply objective functions.
648648
@@ -669,53 +669,277 @@ def mo_generate_plot_grid(variables, resolutions, functions):
669669
return plot_grid
670670

671671

672-
def mo_create_contour_plots(plot_grid, x_col, y_col, z_col, facet_col, z_label="Objective", cmap="viridis", levels=10):
672+
def contour_plot(
673+
data,
674+
x_col,
675+
y_col,
676+
z_col,
677+
facet_col=None,
678+
aspect=1,
679+
as_table=True,
680+
figsize=(4, 4),
681+
levels=10,
682+
cmap="viridis",
683+
highlight_point=None,
684+
highlight_color="red",
685+
highlight_size=50,
686+
highlight_label=None,
687+
highlight_legend_loc="upper right",
688+
highlight_legend_fontsize=8,
689+
) -> None:
690+
"""
691+
Creates contour plots (single or faceted) using matplotlib.
692+
693+
Args:
694+
data (pd.DataFrame): The DataFrame containing the data.
695+
x_col (str): The name of the column to use for the x-axis.
696+
y_col (str): The name of the column to use for the y-axis.
697+
z_col (str): The name of the column to use for the z-axis (contour values).
698+
facet_col (str, optional): The name of the column to use for faceting (creating subplots). Defaults to None.
699+
aspect (float, optional): The aspect ratio of the plot. Defaults to 1.
700+
as_table (bool, optional): Whether to arrange facets as a table. Defaults to True.
701+
figsize (tuple, optional): The size of the figure. Defaults to (4, 4).
702+
levels (int, optional): The number of contour levels. Defaults to 5.
703+
cmap (str, optional): The colormap to use. Defaults to "viridis".
704+
highlight_point (np.array, optional): A 1-dimensional array specifying a single point [x, y] to highlight. Defaults to None.
705+
highlight_color (str, optional): Color for the highlighted point. Defaults to "red".
706+
highlight_size (int, optional): Size of the highlighted point. Defaults to 50.
707+
highlight_label (str, optional): Label for the highlighted point. Defaults to "Highlighted Point".
708+
highlight_legend_loc (str, optional): Location for the legend. Defaults to "upper right".
709+
highlight_legend_fontsize (int, optional): Font size for the legend. Defaults to 8.
710+
711+
Returns:
712+
None: Displays the contour plot(s).
713+
"""
714+
if facet_col:
715+
facet_values = data[facet_col].unique()
716+
num_facets = len(facet_values)
717+
718+
# Determine subplot layout
719+
if as_table:
720+
num_cols = int(np.ceil(np.sqrt(num_facets)))
721+
num_rows = int(np.ceil(num_facets / num_cols))
722+
else:
723+
num_cols = num_facets
724+
num_rows = 1
725+
726+
fig, axes = plt.subplots(num_rows, num_cols, figsize=(figsize[0] * num_cols, figsize[1] * num_rows))
727+
axes = np.array(axes).flatten() # Flatten the axes array for easy indexing
728+
729+
for i, facet_value in enumerate(facet_values):
730+
ax = axes[i]
731+
facet_data = data[data[facet_col] == facet_value]
732+
733+
# Create grid for contour plot
734+
x = np.unique(facet_data[x_col])
735+
y = np.unique(facet_data[y_col])
736+
X, Y = np.meshgrid(x, y)
737+
Z = facet_data.pivot_table(index=y_col, columns=x_col, values=z_col).values
738+
739+
# Plot contour
740+
contour = ax.contour(X, Y, Z, levels=levels, cmap=cmap)
741+
ax.clabel(contour, inline=True, fontsize=8)
742+
743+
# Highlight the specified point
744+
if highlight_point is not None:
745+
ax.scatter(highlight_point[0], highlight_point[1], color=highlight_color, s=highlight_size, label=highlight_label, zorder=10)
746+
if highlight_label:
747+
ax.legend(loc=highlight_legend_loc, fontsize=highlight_legend_fontsize)
748+
749+
# Set labels and title
750+
ax.set_xlabel(x_col)
751+
ax.set_ylabel(y_col)
752+
ax.set_title(f"{facet_col} = {np.round(facet_value, 2)}")
753+
ax.set_aspect(aspect)
754+
755+
# Remove empty subplots
756+
for i in range(num_facets, len(axes)):
757+
fig.delaxes(axes[i])
758+
759+
fig.tight_layout()
760+
plt.show()
761+
762+
else:
763+
# Create grid for contour plot
764+
x = np.unique(data[x_col])
765+
y = np.unique(data[y_col])
766+
X, Y = np.meshgrid(x, y)
767+
Z = data.pivot_table(index=y_col, columns=x_col, values=z_col).values
768+
769+
# Plot contour
770+
fig, ax = plt.subplots(figsize=figsize)
771+
contour = ax.contour(X, Y, Z, levels=levels, cmap=cmap)
772+
ax.clabel(contour, inline=True, fontsize=8)
773+
774+
# Highlight the specified point
775+
if highlight_point is not None:
776+
ax.scatter(highlight_point[0], highlight_point[1], color=highlight_color, s=highlight_size, label=highlight_label, zorder=10)
777+
if highlight_label:
778+
ax.legend(loc=highlight_legend_loc, fontsize=highlight_legend_fontsize)
779+
780+
# Set labels and title
781+
ax.set_xlabel(x_col)
782+
ax.set_ylabel(y_col)
783+
ax.set_title(f"Contour Plot of {z_col}")
784+
ax.set_aspect(aspect)
785+
786+
plt.show()
787+
788+
789+
def contourf_plot(
790+
data,
791+
x_col,
792+
y_col,
793+
z_col,
794+
facet_col=None,
795+
aspect=1,
796+
as_table=True,
797+
figsize=(4, 4),
798+
levels=10,
799+
cmap="viridis",
800+
show_contour_lines=True,
801+
contour_line_color="black",
802+
contour_line_width=0.5,
803+
colorbar_orientation="vertical",
804+
wspace=0.4,
805+
hspace=0.4,
806+
highlight_point=None, # New argument to specify a single point to highlight
807+
highlight_color="red", # Color for the highlighted point
808+
highlight_size=50, # Size of the highlighted point
809+
highlight_label=None, # Label for the highlighted point
810+
highlight_legend_loc="upper right", # Legend location
811+
highlight_legend_fontsize=8, # Font size for the legend
812+
) -> None:
673813
"""
674-
Create contour plots for a given grid of data.
814+
Creates filled contour plots (single or faceted) using matplotlib.
675815
676816
Args:
677-
plot_grid (pd.DataFrame): The data containing the grid and objective values.
678-
x_col (str): The column name for the x-axis.
679-
y_col (str): The column name for the y-axis.
680-
z_col (str): The column name for the z-axis (objective values).
681-
facet_col (str): The column name for the facet (e.g., temperature).
682-
z_label (str): Label for the colorbar.
683-
cmap (str): Colormap for the contour plot.
684-
levels (int): Number of contour levels.
817+
data (pd.DataFrame): The DataFrame containing the data.
818+
x_col (str): The name of the column to use for the x-axis.
819+
y_col (str): The name of the column to use for the y-axis.
820+
z_col (str): The name of the column to use for the z-axis (contour values).
821+
facet_col (str, optional): The name of the column to use for faceting (creating subplots). Defaults to None.
822+
aspect (float, optional): The aspect ratio of the plot. Defaults to 1.
823+
as_table (bool, optional): Whether to arrange facets as a table. Defaults to True.
824+
figsize (tuple, optional): The size of the figure. Defaults to (4, 4).
825+
levels (int, optional): The number of contour levels. Defaults to 10.
826+
cmap (str, optional): The colormap to use. Defaults to "viridis".
827+
show_contour_lines (bool, optional): Whether to overlay contour lines on the filled plot. Defaults to False.
828+
contour_line_color (str, optional): Color of the contour lines. Defaults to "black".
829+
contour_line_width (float, optional): Width of the contour lines. Defaults to 0.5.
830+
colorbar_orientation (str, optional): Orientation of the colorbar ("vertical" or "horizontal"). Defaults to "vertical".
831+
wspace (float, optional): Horizontal spacing between subplots. Defaults to 0.4.
832+
hspace (float, optional): Vertical spacing between subplots. Defaults to 0.4.
833+
highlight_point (np.array, optional): A 1-dimensional array specifying a single point [x, y] to highlight. Defaults to None.
834+
highlight_color (str, optional): Color for the highlighted point. Defaults to "red".
835+
highlight_size (int, optional): Size of the highlighted point. Defaults to 50.
836+
highlight_label (str, optional): Label for the highlighted point. Defaults to None.
837+
highlight_legend_loc (str, optional): Location for the legend. Defaults to "upper right".
838+
highlight_legend_fontsize (int, optional): Font size for the legend. Defaults to 8.
839+
840+
Returns:
841+
None: Displays the filled contour plot(s).
685842
"""
686-
unique_facets = plot_grid[facet_col].unique()
687-
n_facets = len(unique_facets)
843+
if facet_col:
844+
facet_values = data[facet_col].unique()
845+
num_facets = len(facet_values)
688846

689-
# Set up a grid of subplots
690-
n_cols = 2
691-
n_rows = (n_facets + 1) // n_cols
692-
fig = plt.figure(figsize=(12, 5 * n_rows))
693-
gs = gridspec.GridSpec(n_rows, n_cols + 1, width_ratios=[1] * n_cols + [0.05]) # Add space for colorbar
847+
# Determine subplot layout
848+
if as_table:
849+
num_cols = int(np.ceil(np.sqrt(num_facets)))
850+
num_rows = int(np.ceil(num_facets / num_cols))
851+
else:
852+
num_cols = num_facets
853+
num_rows = 1
694854

695-
axes = [fig.add_subplot(gs[i // n_cols, i % n_cols]) for i in range(n_facets)]
855+
# Create figure with gridspec for colorbar placement
856+
if colorbar_orientation == "vertical":
857+
fig = plt.figure(figsize=(figsize[0] * num_cols, figsize[1] * num_rows))
858+
spec = gridspec.GridSpec(num_rows, num_cols + 1, width_ratios=[1] * num_cols + [0.05], wspace=wspace, hspace=hspace)
859+
else: # Horizontal colorbar
860+
fig = plt.figure(figsize=(figsize[0] * num_cols, figsize[1] * num_rows + 1))
861+
spec = gridspec.GridSpec(num_rows + 1, num_cols, height_ratios=[1] * num_rows + [0.05], wspace=wspace, hspace=hspace)
696862

697-
for i, facet in enumerate(unique_facets):
698-
# Filter data for the current facet
699-
facet_data = plot_grid[plot_grid[facet_col] == facet]
863+
axes = []
864+
for row in range(num_rows):
865+
for col in range(num_cols):
866+
if row * num_cols + col < num_facets:
867+
axes.append(fig.add_subplot(spec[row, col]))
700868

701-
# Pivot the data for contour plotting
702-
pivot_table = facet_data.pivot(index=y_col, columns=x_col, values=z_col)
869+
for i, facet_value in enumerate(facet_values):
870+
ax = axes[i]
871+
facet_data = data[data[facet_col] == facet_value]
872+
873+
# Create grid for contour plot
874+
x = np.unique(facet_data[x_col])
875+
y = np.unique(facet_data[y_col])
876+
X, Y = np.meshgrid(x, y)
877+
Z = facet_data.pivot_table(index=y_col, columns=x_col, values=z_col).values
878+
879+
# Plot filled contour
880+
contour = ax.contourf(X, Y, Z, levels=levels, cmap=cmap)
881+
882+
# Optionally overlay contour lines
883+
if show_contour_lines:
884+
contour_lines = ax.contour(X, Y, Z, levels=levels, colors=contour_line_color, linewidths=contour_line_width)
885+
ax.clabel(contour_lines, inline=True, fontsize=8)
886+
887+
# Highlight the specified point
888+
if highlight_point is not None:
889+
ax.scatter(highlight_point[0], highlight_point[1], color=highlight_color, s=highlight_size, label=highlight_label, zorder=10)
890+
if highlight_label:
891+
ax.legend(loc=highlight_legend_loc, fontsize=highlight_legend_fontsize)
892+
893+
# Set labels and title
894+
ax.set_xlabel(x_col)
895+
ax.set_ylabel(y_col)
896+
ax.set_title(f"{facet_col} = {np.round(facet_value, 2)}")
897+
ax.set_aspect(aspect)
898+
899+
# Add colorbar
900+
if colorbar_orientation == "vertical":
901+
cbar_ax = fig.add_subplot(spec[:, -1]) # Last column for vertical colorbar
902+
else:
903+
cbar_ax = fig.add_subplot(spec[-1, :]) # Last row for horizontal colorbar
904+
fig.colorbar(contour, cax=cbar_ax, orientation=colorbar_orientation, label=z_col)
703905

704-
# Create the contour plot
705-
ax = axes[i]
706-
contour = ax.contourf(pivot_table.columns, pivot_table.index, pivot_table.values, cmap=cmap, levels=levels) # x-axis # y-axis # z-axis
707-
contour_lines = ax.contour(pivot_table.columns, pivot_table.index, pivot_table.values, colors="black", linewidths=0.5, levels=levels)
708-
ax.clabel(contour_lines, inline=True, fontsize=8) # Add labels to contour lines
906+
plt.show()
709907

710-
# Set plot labels and title
711-
ax.set_title(f"{facet_col} = {facet:.2f}")
908+
else:
909+
# Create grid for contour plot
910+
x = np.unique(data[x_col])
911+
y = np.unique(data[y_col])
912+
X, Y = np.meshgrid(x, y)
913+
Z = data.pivot_table(index=y_col, columns=x_col, values=z_col).values
914+
915+
# Create figure
916+
fig, ax = plt.subplots(figsize=figsize)
917+
918+
# Plot filled contour
919+
contour = ax.contourf(X, Y, Z, levels=levels, cmap=cmap)
920+
921+
# Optionally overlay contour lines
922+
if show_contour_lines:
923+
contour_lines = ax.contour(X, Y, Z, levels=levels, colors=contour_line_color, linewidths=contour_line_width)
924+
ax.clabel(contour_lines, inline=True, fontsize=8)
925+
926+
# Highlight the specified point
927+
if highlight_point is not None:
928+
ax.scatter(highlight_point[0], highlight_point[1], color=highlight_color, s=highlight_size, label=highlight_label, zorder=10)
929+
if highlight_label:
930+
ax.legend(loc=highlight_legend_loc, fontsize=highlight_legend_fontsize)
931+
932+
# Set labels and title
712933
ax.set_xlabel(x_col)
713934
ax.set_ylabel(y_col)
935+
ax.set_title(f"Filled Contour Plot of {z_col}")
936+
ax.set_aspect(aspect)
714937

715-
# Add a colorbar to the right of the plots
716-
cbar_ax = fig.add_subplot(gs[:, -1]) # Use the last column for the colorbar
717-
fig.colorbar(contour, cax=cbar_ax, orientation="vertical", label=z_label)
938+
# Add colorbar
939+
if colorbar_orientation == "vertical":
940+
cbar_ax = fig.add_axes([0.92, 0.15, 0.02, 0.7]) # Position for vertical colorbar
941+
else:
942+
cbar_ax = fig.add_axes([0.15, 0.05, 0.7, 0.02]) # Position for horizontal colorbar
943+
fig.colorbar(contour, cax=cbar_ax, orientation=colorbar_orientation, label=z_col)
718944

719-
# Adjust layout and show the plot
720-
plt.tight_layout()
721-
plt.show()
945+
plt.show()

src/spotpython/utils/desirability.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ def activity_pred(x) -> float:
10821082
return 59.85 + 3.583 * x[0] + 0.2546 * x[1] + 2.2298 * x[2] + 0.83479 * x[0] ** 2 + 0.07484 * x[1] ** 2 + 0.05716 * x[2] ** 2 - 0.3875 * x[0] * x[1] - 0.375 * x[0] * x[2] + 0.3125 * x[1] * x[2]
10831083

10841084

1085-
def rsm_opt(x, d_object, prediction_funcs, space="square"):
1085+
def rsm_opt(x, d_object, prediction_funcs, space="square") -> float:
10861086
"""
10871087
Optimization function to calculate desirability.
10881088
Optimizers minimize, so we return negative desirability.

0 commit comments

Comments
 (0)