Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: dark mode for plots #911

Merged
merged 21 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a5cdb4c
zwischenstand
saius02 Jul 5, 2024
3ed5e93
colum_plotter darkmode zwischenstand
saius02 Jul 12, 2024
e0bbd97
zwischenstand
saius02 Jul 12, 2024
2d8d625
Resolve merge conflict and keep the snapshot file TestAddNoise.test_s…
TobiasPluecker Jul 12, 2024
514ccdc
Linterfehler gefixt
TobiasPluecker Jul 12, 2024
64da176
Linterproblem gefixt
TobiasPluecker Jul 12, 2024
9e3e3ae
style: apply automated linter fixes
megalinter-bot Jul 12, 2024
17b0982
style: apply automated linter fixes
megalinter-bot Jul 12, 2024
55c916f
Examples Fehlerhaft
TobiasPluecker Jul 12, 2024
e7aa6b8
Merge branch '789-feat-dark-mode-for-plots-neu' of https://github.com…
TobiasPluecker Jul 12, 2024
dab90e7
style: apply automated linter fixes
megalinter-bot Jul 12, 2024
8b594dd
Update src/safeds/data/tabular/plotting/_column_plotter.py
TobiasPluecker Jul 12, 2024
02ce0fe
unnötiger Testcase auskommentiert entgernt
TobiasPluecker Jul 12, 2024
982c5a6
theme parameter documented
TobiasPluecker Jul 12, 2024
2e8f580
Merge branch '789-feat-dark-mode-for-plots-neu' of https://github.com…
TobiasPluecker Jul 12, 2024
3c3038e
Update src/safeds/data/tabular/plotting/_table_plotter.py
TobiasPluecker Jul 12, 2024
dd620f1
style: apply automated linter fixes
megalinter-bot Jul 12, 2024
a464fe6
documentation and remove unnecessary comments
TobiasPluecker Jul 12, 2024
513f18a
Merge branch '789-feat-dark-mode-for-plots-neu' of https://github.com…
TobiasPluecker Jul 12, 2024
2f003dd
style: apply automated linter fixes
megalinter-bot Jul 12, 2024
962dc90
made the theme documentation consistent
TobiasPluecker Jul 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 126 additions & 34 deletions src/safeds/data/tabular/plotting/_column_plotter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Literal

from safeds._utils import _figure_to_image
from safeds._validation._check_columns_are_numeric import _check_column_is_numeric
Expand Down Expand Up @@ -29,10 +29,15 @@ class ColumnPlotter:
def __init__(self, column: Column):
self._column: Column = column

def box_plot(self) -> Image:
def box_plot(self, *, theme: Literal["dark", "light"] = "light") -> Image:
"""
Create a box plot for the values in the column. This is only possible for numeric columns.
TobiasPluecker marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
theme:
The color theme of the plot. Default is "light".

Returns
-------
plot:
Expand All @@ -54,27 +59,84 @@ def box_plot(self) -> Image:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.boxplot(
self._column._series.drop_nulls(),
patch_artist=True,
)

ax.set(title=self._column.name)
ax.set_xticks([])
ax.yaxis.grid(visible=True)
fig.tight_layout()

return _figure_to_image(fig)

def histogram(self, *, max_bin_count: int = 10) -> Image:
def _set_boxplot_colors(box: dict, theme: str) -> None:
if theme == "dark":
for median in box["medians"]:
median.set(color="orange", linewidth=1.5)

for box_part in box["boxes"]:
box_part.set(color="white", linewidth=1.5, facecolor="cyan")

for whisker in box["whiskers"]:
whisker.set(color="white", linewidth=1.5)

for cap in box["caps"]:
cap.set(color="white", linewidth=1.5)

for flier in box["fliers"]:
flier.set(marker="o", color="white", alpha=0.5)
else:
for median in box["medians"]:
median.set(color="orange", linewidth=1.5)

for box_part in box["boxes"]:
box_part.set(color="black", linewidth=1.5, facecolor="blue")

for whisker in box["whiskers"]:
whisker.set(color="black", linewidth=1.5)

for cap in box["caps"]:
cap.set(color="black", linewidth=1.5)

for flier in box["fliers"]:
flier.set(marker="o", color="black", alpha=0.5)

style = "dark_background" if theme == "dark" else "default"
with plt.style.context(style):
if theme == "dark":
plt.rcParams.update(
{
"text.color": "white",
"axes.labelcolor": "white",
"axes.edgecolor": "white",
"xtick.color": "white",
"ytick.color": "white",
"grid.color": "gray",
"grid.linewidth": 0.5,
},
)
else:
plt.rcParams.update(
{
"grid.linewidth": 0.5,
},
)

fig, ax = plt.subplots()
box = ax.boxplot(
self._column._series.drop_nulls(),
patch_artist=True,
)

_set_boxplot_colors(box, theme)

ax.set(title=self._column.name)
ax.set_xticks([])
ax.yaxis.grid(visible=True)
fig.tight_layout()

return _figure_to_image(fig)

def histogram(self, *, max_bin_count: int = 10, theme: Literal["dark", "light"] = "light") -> Image:
"""
Create a histogram for the values in the column.

Parameters
----------
max_bin_count:
The maximum number of bins to use in the histogram. Default is 10.
theme:
The color theme of the plot. Default is "light".

Returns
-------
Expand All @@ -87,16 +149,33 @@ def histogram(self, *, max_bin_count: int = 10) -> Image:
>>> column = Column("test", [1, 2, 3])
>>> histogram = column.plot.histogram()
"""
return self._column.to_table().plot.histograms(max_bin_count=max_bin_count)
import matplotlib.pyplot as plt

def lag_plot(self, lag: int) -> Image:
style = "dark_background" if theme == "dark" else "default"
with plt.style.context(style):
if theme == "dark":
plt.rcParams.update(
{
"text.color": "white",
"axes.labelcolor": "white",
"axes.edgecolor": "white",
"xtick.color": "white",
"ytick.color": "white",
},
)

return self._column.to_table().plot.histograms(max_bin_count=max_bin_count)

def lag_plot(self, lag: int, *, theme: Literal["dark", "light"] = "light") -> Image:
"""
Create a lag plot for the values in the column.
TobiasPluecker marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
lag:
The amount of lag.
theme:
The color theme of the plot. Default is "light".

Returns
-------
Expand All @@ -114,21 +193,34 @@ def lag_plot(self, lag: int) -> Image:
>>> column = Column("values", [1, 2, 3, 4])
>>> image = column.plot.lag_plot(2)
"""
if self._column.row_count > 0:
_check_column_is_numeric(self._column, operation="create a lag plot")

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
series = self._column._series
ax.scatter(
x=series.slice(0, max(len(self._column) - lag, 0)),
y=series.slice(lag),
)
ax.set(
xlabel="y(t)",
ylabel=f"y(t + {lag})",
)
fig.tight_layout()

return _figure_to_image(fig)
style = "dark_background" if theme == "dark" else "default"
with plt.style.context(style):
if theme == "dark":
plt.rcParams.update(
{
"text.color": "white",
"axes.labelcolor": "white",
"axes.edgecolor": "white",
"xtick.color": "white",
"ytick.color": "white",
},
)

if self._column.row_count > 0:
_check_column_is_numeric(self._column, operation="create a lag plot")

fig, ax = plt.subplots()
series = self._column._series
ax.scatter(
x=series.slice(0, max(len(self._column) - lag, 0)),
y=series.slice(lag),
)
ax.set(
xlabel="y(t)",
ylabel=f"y(t + {lag})",
)
fig.tight_layout()

return _figure_to_image(fig)
Loading