Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c764dce
Updated empty_circle to allow color_col to be adjusted for deltadelta
sunroofgod Feb 24, 2024
7c84ae3
Added empty_circle as a plot_kwarg for plotting
sunroofgod Feb 24, 2024
458c3aa
Updated formatting
sunroofgod Feb 25, 2024
e2da55d
Added input parameter validation for new filled parameter
sunroofgod Mar 17, 2024
0e79e1c
Added unit tests for new filled parameter for swarmplot
sunroofgod Mar 17, 2024
397faac
Added baseline images for empty_circle plot aesthetic
sunroofgod Mar 17, 2024
a359186
Added baseline image tests for empty_circle plot aesthetic
sunroofgod Mar 17, 2024
6cc19f8
Updated summary lines for swarm_side='right'
sunroofgod Mar 17, 2024
508bd49
Updated summary lines for swarm_side='right'
sunroofgod Mar 17, 2024
c71a4ee
Resolve merge conflicts wrt asymmetric swarmplots and vnbdev branch
sunroofgod Mar 19, 2024
319f513
Fixed bug involving empty_circle filled dots feature not working as i…
sunroofgod Mar 22, 2024
8e63177
Merge pull request #176 from ACCLAB/v2024.03.29
Jacobluke- Mar 22, 2024
085a006
Merge pull request #177 from ACCLAB/v2024.03.29
Jacobluke- Mar 22, 2024
97585d1
Merge pull request #178 from ACCLAB/v2024.03.29
Jacobluke- Mar 22, 2024
ff3a06f
Updated swarmplot to produce legends if plotting by hue column
sunroofgod Mar 24, 2024
9f33da3
Updated errorbar handling of xspans to properly account for when hue …
sunroofgod Mar 24, 2024
8edb941
Updated errorbar handling of xspans to properly account for when hue …
sunroofgod Mar 24, 2024
4b928b7
Updated swarmplot to produce legends if plotting by hue column
sunroofgod Mar 24, 2024
d712e8e
Fix non-string input issue
Jacobluke- Mar 25, 2024
e5b26a1
Fix an error causing xtick label wrong
Jacobluke- Mar 25, 2024
001fa49
Merge remote-tracking branch 'upstream/master' into feat-asymmetric-s…
Jacobluke- Sep 20, 2024
df50e25
Resolve conflicts for empty_circle and Seaborn params
Jacobluke- Sep 23, 2024
533797c
Regenerate test image baseline
Jacobluke- Sep 23, 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
9 changes: 8 additions & 1 deletion dabest/_effsize_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,7 @@ def plot(
contrast_ylim=None,
delta2_ylim=None,
swarm_side=None,
empty_circle=False,
custom_palette=None,
swarm_desat=0.5,
halfviolin_desat=1,
Expand Down Expand Up @@ -1064,6 +1065,12 @@ def plot(
https://seaborn.pydata.org/generated/seaborn.cubehelix_palette.html
The named colors of matplotlib can be found here:
https://matplotlib.org/examples/color/named_colors.html
swarm_side: string, default None
The side on which points are swarmed for swarmplots ("center", "left", or "right").
empty_circle: boolean, default False
Boolean value determining if empty circles will be used for plotting of
swarmplot for control groups. Color of each individual swarm is also now
dependent on the comparison group.
swarm_desat : float, default 1
Decreases the saturation of the colors in the swarmplot by the
desired proportion. Uses `seaborn.desaturate()` to acheive this.
Expand Down Expand Up @@ -1180,7 +1187,7 @@ def plot(
if hasattr(self, "results") is False:
self.__pre_calc()

if self.__delta2:
if self.__delta2 and not empty_circle:
color_col = self.__x2

# if self.__proportional:
Expand Down
87 changes: 76 additions & 11 deletions dabest/plot_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,23 @@ def error_bar(

kwargs["zorder"] = kwargs["zorder"]

for xpos, central_measure in enumerate(central_measures):
for xpos, val in enumerate(central_measures.index):
central_measure = central_measures[val]
kwargs["color"] = custom_palette[xpos]

if method == "sankey_error_bar":
_xpos = pos[xpos] + offset[xpos]
else:
_xpos = xpos + offset[xpos]

low = lows[xpos]
high = highs[xpos]
# Fix for the non-string x-axis issue #108
if central_measures.index.dtype.name == "category":
low = lows[xpos]
high = highs[xpos]
else:
low = lows[val]
high = highs[val]

if low == high == central_measure:
low_to_mean = mlines.Line2D(
[_xpos, _xpos], [low, central_measure], **kwargs
Expand Down Expand Up @@ -791,6 +798,7 @@ def swarmplot(
size: float = 5,
side: str = "center",
jitter: float = 1,
filled: Union[bool, List, Tuple] = True,
is_drop_gutter: bool = True,
gutter_limit: float = 0.5,
**kwargs,
Expand Down Expand Up @@ -823,6 +831,11 @@ def swarmplot(
The side on which points are swarmed ("center", "left", or "right"). Default is "center".
jitter : int | float
Determines the distance between points. Default is 1.
filled : bool | List | Tuple
Determines whether the dots in the swarmplot are filled or not. If set to False,
dots are not filled. If provided as a List or Tuple, it should contain boolean values,
each corresponding to a swarm group in order, indicating whether the dot should be
filled or not.
is_drop_gutter : bool
If True, drop points that hit the gutters; otherwise, readjust them.
gutter_limit : int | float
Expand All @@ -836,7 +849,7 @@ def swarmplot(
Matplotlib AxesSubplot object for which the swarm plot has been drawn on.
"""
s = SwarmPlot(data, x, y, ax, order, hue, palette, zorder, size, side, jitter)
ax = s.plot(is_drop_gutter, gutter_limit, ax, **kwargs)
ax = s.plot(is_drop_gutter, gutter_limit, ax, filled, **kwargs)
return ax


Expand Down Expand Up @@ -996,7 +1009,9 @@ def _check_errors(
if not isinstance(self.__jitter, (int, float)):
raise ValueError("`jitter` must be a scalar or float.")
if not isinstance(self.__palette, (str, Iterable)):
raise ValueError("`palette` must be either a string indicating a color name or an Iterable.")
raise ValueError(
"`palette` must be either a string indicating a color name or an Iterable."
)
if self.__hue is not None and not isinstance(self.__hue, str):
raise ValueError("`hue` must be either a string or None.")
if self.__order is not None and not isinstance(self.__order, Iterable):
Expand Down Expand Up @@ -1026,7 +1041,6 @@ def _check_errors(
err = "`palette` cannot be an empty string. It must be either a string indicating a color name or an Iterable."
raise ValueError(err)
if isinstance(self.__palette, dict):
# TODO: to add detection of when dict length is less than size of unique_items
for group_i, color_i in self.__palette.items():
if group_i not in pd.unique(data[color_col]):
err = (
Expand All @@ -1036,8 +1050,10 @@ def _check_errors(
)
raise IndexError(err)
if isinstance(color_i, str) and color_i.strip() == "":
err = "The color mapping for {0} in `palette` is an empty string. It must contain a color name.".format(group_i)
raise ValueError(err)
err = "The color mapping for {0} in `palette` is an empty string. It must contain a color name.".format(
group_i
)
raise ValueError(err)

if side.lower() not in ["center", "right", "left"]:
raise ValueError(
Expand Down Expand Up @@ -1239,7 +1255,12 @@ def _adjust_gutter_points(
return points_data

def plot(
self, is_drop_gutter: bool, gutter_limit: float, ax: axes.Subplot, **kwargs
self,
is_drop_gutter: bool,
gutter_limit: float,
ax: axes.Subplot,
filled: Union[bool, List, Tuple],
**kwargs,
) -> axes.Subplot:
"""
Generate a swarm plot.
Expand All @@ -1252,6 +1273,11 @@ def plot(
The limit for points hitting the gutters.
ax : axes.Subplot
The matplotlib figure object to which the swarm plot will be added.
filled : bool | List | Tuple
Determines whether the dots in the swarmplot are filled or not. If set to False,
dots are not filled. If provided as a List or Tuple, it should contain boolean values,
each corresponding to a swarm group in order, indicating whether the dot should be
filled or not.
**kwargs:
Additional keyword arguments to be passed to the scatter plot.

Expand All @@ -1265,12 +1291,28 @@ def plot(
raise ValueError("`is_drop_gutter` must be a boolean.")
if not isinstance(gutter_limit, (int, float)):
raise ValueError("`gutter_limit` must be a scalar or float.")
if not isinstance(filled, (bool, list, tuple)):
raise ValueError("`filled` must be a boolean, list or tuple.")

# More thorough input validation checks
if isinstance(filled, (list, tuple)):
if len(filled) != len(self.__order):
err = (
"There are {0} unique values in `x` column in `data` "
"but `filled` has a length of {1}. If `filled` is a list "
"or a tuple, it must have the same length as the number of "
"unique values/groups in the `x` column of data."
).format(len(self.__order), len(filled))
raise ValueError(err)
if not all(isinstance(_, bool) for _ in filled):
raise ValueError("All values in `filled` must be a boolean.")

# Assumptions are that self.__data_copy is already sorted according to self.__order
x_position = (
0 # x-coordinate of center of each individual swarm of the swarm plot
)
x_tick_tabels = []

for group_i, values_i in self.__data_copy.groupby(self.__x):
x_new = []
values_i_y = values_i[self.__y]
Expand Down Expand Up @@ -1321,16 +1363,39 @@ def plot(
)
else:
# color swarms based on `x` column
if not isinstance(filled, bool):
facecolor = (
"none"
if not filled[x_position - 1]
else self.__palette[group_i]
)
else:
facecolor = "none" if not filled else self.__palette[group_i]

ax.scatter(
values_i["x_new"],
values_i[self.__y],
s=self.__size,
c=self.__palette[group_i],
zorder=self.__zorder,
edgecolor="face",
facecolor=facecolor,
edgecolor=self.__palette[group_i],
label=group_i,
**kwargs,
)

# Handling of legends
# This is currently a workaround because c and cmap is unable to map the labels when calling scatter()
# labels has to be used to designate legend labels and handles in scatter() due to the potential calling of ax.get_legend_handles_labels()
if self.__hue is not None:
for cmap_group_i in self.__palette:
ax.scatter(
[],
[],
c=self.__palette[cmap_group_i],
label=cmap_group_i,
)
handles, labels = ax.get_legend_handles_labels()

ax.get_xaxis().set_ticks(np.arange(x_position))
ax.get_xaxis().set_ticklabels(x_tick_tabels)

Expand Down
Loading