8000 Cleanup demo_agg_filter. by anntzer · Pull Request #14961 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Cleanup demo_agg_filter. #14961

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

Merged
merged 1 commit into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
134 changes: 46 additions & 88 deletions examples/misc/demo_agg_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,82 @@
===============

"""
import matplotlib.pyplot as plt

import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
from matplotlib.colors import LightSource
from matplotlib.artist import Artist
import numpy as np


def smooth1d(x, window_len):
# copied from http://www.scipy.org/Cookbook/SignalSmooth

s = np.r_[2*x[0] - x[window_len:1:-1], x, 2*x[-1] - x[-1:-window_len:-1]]
w = np.hanning(window_len)
y = np.convolve(w/w.sum(), s, mode='same')
return y[window_len-1:-window_len+1]


def smooth2d(A, sigma=3):

window_len = max(int(sigma), 3)*2 + 1
A1 = np.array([smooth1d(x, window_len) for x in np.asarray(A)])
A2 = np.transpose(A1)
A3 = np.array([smooth1d(x, window_len) for x in A2])
A4 = np.transpose(A3)

return A4
window_len = max(int(sigma), 3) * 2 + 1
A = np.apply_along_axis(smooth1d, 0, A, window_len)
A = np.apply_along_axis(smooth1d, 1, A, window_len)
return A


class BaseFilter:
def prepare_image(self, src_image, dpi, pad):
ny, nx, depth = src_image.shape
# tgt_image = np.zeros([pad*2+ny, pad*2+nx, depth], dtype="d")
padded_src = np.zeros([pad*2 + ny, pad*2 + nx, depth], dtype="d")
padded_src[pad:-pad, pad:-pad, :] = src_image[:, :, :]

return padded_src # , tgt_image

def get_pad(self, dpi):
return 0

def process_image(padded_src, dpi):
raise NotImplementedError("Should be overridden by subclasses")

def __call__(self, im, dpi):
pad = self.get_pad(dpi)
padded_src = self.prepare_image(im, dpi, pad)
padded_src = np.pad(im, [(pad, pad), (pad, pad), (0, 0)], "constant")
tgt_image = self.process_image(padded_src, dpi)
return tgt_image, -pad, -pad


class OffsetFilter(BaseFilter):
def __init__(self, offsets=None):
if offsets is None:
self.offsets = (0, 0)
else:
self.offsets = offsets

def __init__(self, offsets=(0, 0)):
self.offsets = offsets

def get_pad(self, dpi):
return int(max(*self.offsets)/72.*dpi)
return int(max(self.offsets) / 72 * dpi)

def process_image(self, padded_src, dpi):
ox, oy = self.offsets
a1 = np.roll(padded_src, int(ox/72.*dpi), axis=1)
a2 = np.roll(a1, -int(oy/72.*dpi), axis=0)
a1 = np.roll(padded_src, int(ox / 72 * dpi), axis=1)
a2 = np.roll(a1, -int(oy / 72 * dpi), axis=0)
return a2


class GaussianFilter(BaseFilter):
"simple gauss filter"
"""Simple Gaussian filter."""

def __init__(self, sigma, alpha=0.5, color=None):
def __init__(self, sigma, alpha=0.5, color=(0, 0, 0)):
self.sigma = sigma
self.alpha = alpha
if color is None:
self.color = (0, 0, 0)
else:
self.color = color
self.color = color

def get_pad(self, dpi):
return int(self.sigma*3/72.*dpi)
return int(self.sigma*3 / 72 * dpi)

def process_image(self, padded_src, dpi):
# offsetx, offsety = int(self.offsets[0]), int(self.offsets[1])
tgt_image = np.zeros_like(padded_src)
aa = smooth2d(padded_src[:, :, -1]*self.alpha,
self.sigma/72.*dpi)
tgt_image[:, :, -1] = aa
tgt_image[:, :, :-1] = self.color
tgt_image = np.empty_like(padded_src)
tgt_image[:, :, :3] = self.color
tgt_image[:, :, 3] = smooth2d(padded_src[:, :, 3] * self.alpha,
self.sigma / 72 * dpi)
return tgt_image


class DropShadowFilter(BaseFilter):
def __init__(self, sigma, alpha=0.3, color=None, offsets=None):

def __init__(self, sigma, alpha=0.3, color=(0, 0, 0), offsets=(0, 0)):
self.gauss_filter = GaussianFilter(sigma, alpha, color)
self.offset_filter = OffsetFilter(offsets)

Expand All @@ -109,7 +94,6 @@ def process_image(self, padded_src, dpi):


class LightFilter(BaseFilter):
"simple gauss filter"

def __init__(self, sigma, fraction=0.5):
self.gauss_filter = GaussianFilter(sigma, alpha=1)
Expand All @@ -123,47 +107,36 @@ def process_image(self, padded_src, dpi):
t1 = self.gauss_filter.process_image(padded_src, dpi)
elevation = t1[:, :, 3]
rgb = padded_src[:, :, :3]

alpha = padded_src[:, :, 3:]
rgb2 = self.light_source.shade_rgb(rgb, elevation,
fraction=self.fraction)

tgt = np.empty_like(padded_src)
tgt[:, :, :3] = rgb2
tgt[:, :, 3] = padded_src[:, :, 3]

return tgt
return np.concatenate([rgb2, alpha], -1)


class GrowFilter(BaseFilter):
"enlarge the area"
"""Enlarge the area."""

def __init__(self, pixels, color=None):
def __init__(self, pixels, color=(1, 1, 1)):
self.pixels = pixels
if color is None:
self.color = (1, 1, 1)
else:
self.color = color
self.color = color

def __call__(self, im, dpi):
ny, nx, depth = im.shape
alpha = np.pad(im[..., -1], self.pixels, "constant")
alpha2 = np.clip(smooth2d(alpha, self.pixels/72.*dpi) * 5, 0, 1)
alpha = np.pad(im[..., 3], self.pixels, "constant")
alpha2 = np.clip(smooth2d(alpha, self.pixels / 72 * dpi) * 5, 0, 1)
new_im = np.empty((*alpha2.shape, 4))
new_im[:, :, -1] = alpha2
new_im[:, :, :-1] = self.color
new_im[:, :, :3] = self.color
new_im[:, :, 3] = alpha2
offsetx, offsety = -self.pixels, -self.pixels
return new_im, offsetx, offsety


class FilteredArtistList(Artist):
"""
A simple container to draw filtered artist.
"""
"""A simple container to filter multiple artists at once."""

def __init__(self, artist_list, filter):
super().__init__()
self._artist_list = artist_list
self._filter = filter
Artist.__init__(self)

def draw(self, renderer):
renderer.start_rasterizing()
Expand All @@ -188,15 +161,13 @@ def filtered_text(ax):

# draw
ax.imshow(Z, interpolation='bilinear', origin='lower',
cmap=cm.gray, extent=(-3, 3, -2, 2))
cmap=cm.gray, extent=(-3, 3, -2, 2), aspect='auto')
levels = np.arange(-1.2, 1.6, 0.2)
CS = ax.contour(Z, levels,
origin='lower',
linewidths=2,
extent=(-3, 3, -2, 2))

ax.set_aspect("auto")

# contour label
cl = ax.clabel(CS, levels[1::2], # label every second level
inline=1,
Expand All @@ -223,17 +194,14 @@ def drop_shadow_line(ax):
# copied from examples/misc/svg_filter_line.py

# draw lines
l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-",
mec="b", mfc="w", lw=5, mew=3, ms=10, label="Line 1")
l2, = ax.plot([0.1, 0.5, 0.9], [0.5, 0.2, 0.7], "ro-",
mec="r", mfc="w", lw=5, mew=3, ms=10, label="Line 1")
l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-")
l2, = ax.plot([0.1, 0.5, 0.9], [0.5, 0.2, 0.7], "ro-")

gauss = DropShadowFilter(4)

for l in [l1, l2]:

# draw shadows with same lines with slight offset.

xx = l.get_xdata()
yy = l.get_ydata()
shadow, = ax.plot(xx, yy)
Expand Down Expand Up @@ -288,7 +256,6 @@ def light_filter_pie(ax):
fracs = [15, 30, 45, 10]
explode = (0, 0.05, 0, 0)
pies = ax.pie(fracs, explode=explode)
ax.patch.set_visible(True)

light_filter = LightFilter(9)
for p in pies[0]:
Expand All @@ -305,21 +272,12 @@ def light_filter_pie(ax):

if __name__ == "__main__":

plt.figure(figsize=(6, 6))
plt.subplots_adjust(left=0.05, right=0.95)

ax = plt.subplot(221)
filtered_text(ax)

ax = plt.subplot(222)
drop_shadow_line(ax)

ax = plt.subplot(223)
drop_shadow_patches(ax)
fix, axs = plt.subplots(2, 2)

ax = plt.subplot(224)
ax.set_aspect(1)
light_filter_pie(ax)
ax.set_frame_on(True)
filtered_text(axs[0, 0])
drop_shadow_line(axs[0, 1])
drop_shadow_patches(axs[1, 0])
light_filter_pie(axs[1, 1])
axs[1, 1].set_frame_on(True)

plt.show()
70 changes: 29 additions & 41 deletions lib/matplotlib/tests/test_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,79 +81,69 @@ def test_long_path():
@image_comparison(['agg_filter.png'], remove_text=True)
def test_agg_filter():
def smooth1d(x, window_len):
s = np.r_[2*x[0] - x[window_len:1:-1],
x,
2*x[-1] - x[-1:-window_len:-1]]
# copied from http://www.scipy.org/Cookbook/SignalSmooth
s = np.r_[
2*x[0] - x[window_len:1:-1], x, 2*x[-1] - x[-1:-window_len:-1]]
w = np.hanning(window_len)
y = np.convolve(w/w.sum(), s, mode='same')
return y[window_len-1:-window_len+1]

def smooth2d(A, sigma=3):
window_len = max(int(sigma), 3)*2 + 1
A1 = np.array([smooth1d(x, window_len) for x in np.asarray(A)])
A2 = np.transpose(A1)
A3 = np.array([smooth1d(x, window_len) for x in A2])
A4 = np.transpose(A3)

return A4
window_len = max(int(sigma), 3) * 2 + 1
A = np.apply_along_axis(smooth1d, 0, A, window_len)
A = np.apply_along_axis(smooth1d, 1, A, window_len)
return A

class BaseFilter:
def prepare_image(self, src_image, dpi, pad):
ny, nx, depth = src_image.shape
padded_src = np.zeros([pad*2 + ny, pad*2 + nx, depth], dtype="d")
padded_src[pad:-pad, pad:-pad, :] = src_image[:, :, :]

return padded_src # , tgt_image

def get_pad(self, dpi):
return 0

def process_image(padded_src, dpi):
raise NotImplementedError("Should be overridden by subclasses")

def __call__(self, im, dpi):
pad = self.get_pad(dpi)
padded_src = self.prepare_image(im, dpi, pad)
padded_src = np.pad(im, [(pad, pad), (pad, pad), (0, 0)],
"constant")
tgt_image = self.process_image(padded_src, dpi)
return tgt_image, -pad, -pad

class OffsetFilter(BaseFilter):
def __init__(self, offsets=None):
if offsets is None:
self.offsets = (0, 0)
FAA8 else:
self.offsets = offsets

def __init__(self, offsets=(0, 0)):
self.offsets = offsets

def get_pad(self, dpi):
return int(max(*self.offsets)/72.*dpi)
return int(max(self.offsets) / 72 * dpi)

def process_image(self, padded_src, dpi):
ox, oy = self.offsets
a1 = np.roll(padded_src, int(ox/72.*dpi), axis=1)
a2 = np.roll(a1, -int(oy/72.*dpi), axis=0)
a1 = np.roll(padded_src, int(ox / 72 * dpi), axis=1)
a2 = np.roll(a1, -int(oy / 72 * dpi), axis=0)
return a2

class GaussianFilter(BaseFilter):
"simple gauss filter"
"""Simple Gaussian filter."""

def __init__(self, sigma, alpha=0.5, color=None):
def __init__(self, sigma, alpha=0.5, color=(0, 0, 0)):
self.sigma = sigma
self.alpha = alpha
if color is None:
self.color = (0, 0, 0)
else:
self.color = color
self.color = color

def get_pad(self, dpi):
return int(self.sigma*3/72.*dpi)
return int(self.sigma*3 / 72 * dpi)

def process_image(self, padded_src, dpi):
tgt_image = np.zeros_like(padded_src)
aa = smooth2d(padded_src[:, :, -1]*self.alpha,
self.sigma/72.*dpi)
tgt_image[:, :, -1] = aa
tgt_image[:, :, :-1] = self.color
tgt_image = np.empty_like(padded_src)
tgt_image[:, :, :3] = self.color
tgt_image[:, :, 3] = smooth2d(padded_src[:, :, 3] * self.alpha,
self.sigma / 72 * dpi)
return tgt_image

class DropShadowFilter(BaseFilter):
def __init__(self, sigma, alpha=0.3, color=None, offsets=None):

def __init__(self, sigma, alpha=0.3, color=(0, 0, 0), offsets=(0, 0)):
self.gauss_filter = GaussianFilter(sigma, alpha, color)
self.offset_filter = OffsetFilter(offsets)

Expand All @@ -166,8 +156,7 @@ def process_image(self, padded_src, dpi):
t2 = self.offset_filter.process_image(t1, dpi)
return t2

fig = plt.figure()
ax = fig.add_subplot(111)
fig, ax = plt.subplots()

# draw lines
l1, = ax.plot([0.1, 0.5, 0.9], [0.1, 0.9, 0.5], "bo-",
Expand All @@ -180,7 +169,6 @@ def process_image(self, padded_src, dpi):
for l in [l1, l2]:

# draw shadows with same lines with slight offset.

xx = l.get_xdata()
yy = l.get_ydata()
shadow, = ax.plot(xx, yy)
Expand Down
0