Skip to content

Commit

Permalink
feat: added colouring invidual boxes in boxplot (#20)
Browse files Browse the repository at this point in the history
Co-authored-by: Julien Lerat <[email protected]>
  • Loading branch information
fre171csiro and jlerat authored Mar 12, 2024
1 parent 90a6d7e commit 192f843
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 8 deletions.
51 changes: 44 additions & 7 deletions hydrodiy/plot/boxplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ def draw(self, ax=None, logscale=False, xoffset=0.):
# Draw whiskers
item = self.whiskers
if item.show_line:
for cc in [[wqq1txt, bqq1txt], [wqq2txt, bqq2txt]]:
wnames = [[wqq1txt, bqq1txt], [wqq2txt, bqq2txt]]
for icc, cc in enumerate(wnames):
# Get y data
q1 = stats.loc[cc[0], colname]
q2 = stats.loc[cc[1], colname]
Expand All @@ -606,8 +607,8 @@ def draw(self, ax=None, logscale=False, xoffset=0.):
ax.plot(x, y, lw=item.linewidth,
color=item.linecolor, \
alpha=item.alpha)
element["bottom-whiskers"] = ax.get_lines()[-2]
element["top-whiskers"] = ax.get_lines()[-1]
element[f"bottom-whiskers{icc+1}"] = ax.get_lines()[-2]
element[f"top-whiskers{icc+1}"] = ax.get_lines()[-1]
else:
# Draw box
bbox = FancyBboxPatch([i-ww/2+xoffset, q1], \
Expand All @@ -619,24 +620,24 @@ def draw(self, ax=None, logscale=False, xoffset=0.):
alpha=item.alpha)

ax.add_patch(bbox)
element["whiskers"] = ax.patches[-1]
element[f"whiskers{icc+1}"] = ax.patches[-1]

# Cap width
cw = capswidths[i]

# Draw caps
item = self.caps
if item.show_line and cw>0:
for qq in [wqq1txt, wqq2txt]:
for iqq, qq in enumerate([wqq1txt, wqq2txt]):
q1 = stats.loc[qq, colname]
x = [i-cw/5+xoffset, i+cw/5+xoffset]
y = [q1]*2
ax.plot(x, y, lw=item.linewidth,
color=item.linecolor, \
alpha=item.alpha)

element["bottom-cap"] = ax.get_lines()[-2]
element["top-cap"] = ax.get_lines()[-1]
element[f"bottom-cap{iqq+1}"] = ax.get_lines()[-2]
element[f"top-cap{iqq+1}"] = ax.get_lines()[-1]

# Box (quartile) values
item = self.box
Expand Down Expand Up @@ -793,3 +794,39 @@ def set_ylim(self, ylim, hide_offlimit_text=True):

# Set axis limits
self.ax.set_ylim(ylim)


def set_color(self, name_pattern, color, alpha=0.5):
""" Set color for selected boxes identied by
name_pattern.
Parameters
-----------
name_pattern : str
Pattern selection for box selection.
color : str
Color to set
alpha : float
Transparency level.
"""
props = ["color", "linecolor", \
"edgecolor", "markeredgecolor", \
"facecolor"]

for ename, elems in self.elements.items():
if not re.search(name_pattern, ename):
continue

for on, obj in elems.items():
for prop in props:
# Set color to element.
# Try all properties with try
try:
fun = getattr(obj, f"set_{prop}")
fun(color)
except:
pass

if re.search("box", on):
obj.set_alpha(alpha)

31 changes: 30 additions & 1 deletion hydrodiy/plot/tests/test_hyplot_boxplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def test_width_by_count():


def test_coverage():
plt.close("all")
fig, axs = plt.subplots(ncols=2)

bx1 = Boxplot(data=DATA)
Expand All @@ -150,6 +151,7 @@ def test_coverage():


def test_coverage_by():
plt.close("all")
fig, ax = plt.subplots()
cat = DATA["cat"].copy()
cat.loc[cat<3] = 0
Expand All @@ -160,6 +162,7 @@ def test_coverage_by():


def test_item_change():
plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(data=DATA)
bx.median.textformat = "%0.4f"
Expand All @@ -169,6 +172,7 @@ def test_item_change():


def test_center():
plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(data=DATA)
bx.median.va = "bottom"
Expand Down Expand Up @@ -197,6 +201,7 @@ def test_narrow():
df = pd.DataFrame(np.random.normal(size=(nval, nvar)), \
columns = ["data{0}".format(i) for i in range(nvar)])

plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(style="narrow", data=df)
bx.draw(ax=ax)
Expand All @@ -209,6 +214,7 @@ def test_showtext():
df = pd.DataFrame(np.random.normal(size=(nval, nvar)), \
columns = ["data{0}".format(i) for i in range(nvar)])

plt.close("all")
fig, axs = plt.subplots(ncols=2)
bx = Boxplot(data=df)
bx.draw(ax=axs[0])
Expand All @@ -225,6 +231,7 @@ def test_center_text():
df = pd.DataFrame(np.random.normal(size=(nval, nvar)), \
columns = ["data{0}".format(i) for i in range(nvar)])

plt.close("all")
fig, axs = plt.subplots(ncols=2)
bx = Boxplot(data=df)
bx.draw(ax=axs[0])
Expand All @@ -241,13 +248,15 @@ def test_number_format():
df = pd.DataFrame(np.random.normal(size=(nval, nvar)), \
columns = ["data{0}".format(i) for i in range(nvar)])

plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(data=df, number_format="3.3e")
bx.draw(ax=ax)
fig.savefig(FIMG /"bx18_number_format.png")


def test_change_elements():
plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(data=DATA, show_text=True)
bx.draw(ax=ax)
Expand All @@ -257,7 +266,7 @@ def test_change_elements():
line.set_solid_capstyle("round")
line.set_linewidth(8)

line = bx.elements["data1"]["top-cap"]
line = bx.elements["data1"]["top-cap1"]
line.set_color("green")
line.set_solid_capstyle("round")
line.set_linewidth(6)
Expand All @@ -270,6 +279,7 @@ def test_change_elements():


def test_set_ylim():
plt.close("all")
fig, axs = plt.subplots(ncols=2)
ax = axs[0]
bx = Boxplot(data=DATA)
Expand All @@ -282,3 +292,22 @@ def test_set_ylim():
bx.set_ylim((1, y1), False)

fig.savefig(FIMG /"bx20_set_ylim.png")


def test_set_color():
plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(data=DATA)
bx.draw(ax=ax)
bx.set_color(".*a2$", "tab:red")

fig.savefig(FIMG /"bx21_set_color.png")

plt.close("all")
fig, ax = plt.subplots()
bx = Boxplot(data=DATA, style="narrow")
bx.draw(ax=ax)
bx.set_color(".*a2$", "tab:red")

fig.savefig(FIMG /"bx22_set_color_narrow.png")

0 comments on commit 192f843

Please sign in to comment.