Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit df066b5

Browse files
committed
BboxImage implemented and two examples added.
svn path=/trunk/matplotlib/; revision=7423
1 parent e4bfcc0 commit df066b5

4 files changed

Lines changed: 350 additions & 0 deletions

File tree

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2009-08-07 BboxImage implemented. Two examples, demo_bboximage.py and
2+
demo_ribbon_box.py added. - JJL
3+
14
2009-08-07 In an effort to simplify the backend API, all clipping rectangles
25
and paths are now passed in using GraphicsContext objects, even
36
on collections and images. Therefore:
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
from matplotlib.image import BboxImage
4+
from matplotlib.transforms import Bbox, TransformedBbox
5+
6+
if __name__ == "__main__":
7+
8+
fig = plt.figure(1)
9+
ax = plt.subplot(121)
10+
11+
txt = ax.text(0.5, 0.5, "test", size=30, ha="center", color="w")
12+
kwargs = dict()
13+
14+
bbox_image = BboxImage(txt.get_window_extent,
15+
norm = None,
16+
origin=None,
17+
clip_on=False,
18+
**kwargs
19+
)
20+
a = np.arange(256).reshape(1,256)/256.
21+
bbox_image.set_data(a)
22+
ax.add_artist(bbox_image)
23+
24+
25+
ax = plt.subplot(122)
26+
a = np.linspace(0, 1, 256).reshape(1,-1)
27+
a = np.vstack((a,a))
28+
29+
maps = sorted(m for m in plt.cm.datad if not m.endswith("_r"))
30+
#nmaps = len(maps) + 1
31+
32+
#fig.subplots_adjust(top=0.99, bottom=0.01, left=0.2, right=0.99)
33+
34+
ncol = 2
35+
nrow = len(maps)//ncol + 1
36+
37+
xpad_fraction = 0.3
38+
dx = 1./(ncol + xpad_fraction*(ncol-1))
39+
40+
ypad_fraction = 0.3
41+
dy = 1./(nrow + ypad_fraction*(nrow-1))
42+
43+
for i,m in enumerate(maps):
44+
ix, iy = divmod(i, nrow)
45+
#plt.figimage(a, 10, i*10, cmap=plt.get_cmap(m), origin='lower')
46+
bbox0 = Bbox.from_bounds(ix*dx*(1+xpad_fraction),
47+
1.-iy*dy*(1+ypad_fraction)-dy,
48+
dx, dy)
49+
bbox = TransformedBbox(bbox0, ax.transAxes)
50+
51+
bbox_image = BboxImage(bbox,
52+
cmap = plt.get_cmap(m),
53+
norm = None,
54+
origin=None,
55+
**kwargs
56+
)
57+
58+
bbox_image.set_data(a)
59+
ax.add_artist(bbox_image)
60+
61+
plt.draw()
62+
plt.show()
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import matplotlib.pyplot as plt
2+
import numpy as np
3+
from matplotlib.image import BboxImage
4+
5+
from matplotlib._png import read_png
6+
import matplotlib.colors
7+
from matplotlib.cbook import get_sample_data
8+
9+
class RibbonBox(object):
10+
11+
original_image = read_png(get_sample_data("Minduka_Present_Blue_Pack.png",
12+
asfileobj=False))
13+
cut_location = 70
14+
b_and_h = original_image[:,:,2]
15+
color = original_image[:,:,2] - original_image[:,:,0]
16+
alpha = original_image[:,:,3]
17+
nx = original_image.shape[1]
18+
19+
def __init__(self, color):
20+
rgb = matplotlib.colors.colorConverter.to_rgb(color)
21+
22+
im = np.empty(self.original_image.shape,
23+
self.original_image.dtype)
24+
25+
26+
im[:,:,:3] = self.b_and_h[:,:,np.newaxis]
27+
im[:,:,:3] -= self.color[:,:,np.newaxis]*(1.-np.array(rgb))
28+
im[:,:,3] = self.alpha
29+
30+
self.im = im
31+
32+
33+
def get_stretched_image(self, stretch_factor):
34+
stretch_factor = max(stretch_factor, 1)
35+
ny, nx, nch = self.im.shape
36+
ny2 = int(ny*stretch_factor)
37+
38+
stretched_image = np.empty((ny2, nx, nch),
39+
self.im.dtype)
40+
cut = self.im[self.cut_location,:,:]
41+
stretched_image[:,:,:] = cut
42+
stretched_image[:self.cut_location,:,:] = \
43+
self.im[:self.cut_location,:,:]
44+
stretched_image[-(ny-self.cut_location):,:,:] = \
45+
self.im[-(ny-self.cut_location):,:,:]
46+
47+
self._cached_im = stretched_image
48+
return stretched_image
49+
50+
51+
52+
class RibbonBoxImage(BboxImage):
53+
zorder = 1
54+
55+
def __init__(self, bbox, color,
56+
cmap = None,
57+
norm = None,
58+
interpolation=None,
59+
origin=None,
60+
filternorm=1,
61+
filterrad=4.0,
62+
resample = False,
63+
**kwargs
64+
):
65+
66+
BboxImage.__init__(self, bbox,
67+
cmap = None,
68+
norm = None,
69+
interpolation=None,
70+
origin=None,
71+
filternorm=1,
72+
filterrad=4.0,
73+
resample = False,
74+
**kwargs
75+
)
76+
77+
self._ribbonbox = RibbonBox(color)
78+
self._cached_ny = None
79+
80+
81+
def draw(self, renderer, *args, **kwargs):
82+
83+
bbox = self.get_window_extent(renderer)
84+
stretch_factor = bbox.height / bbox.width
85+
86+
ny = int(stretch_factor*self._ribbonbox.nx)
87+
if self._cached_ny != ny:
88+
arr = self._ribbonbox.get_stretched_image(stretch_factor)
89+
self.set_array(arr)
90+
self._cached_ny = ny
91+
92+
BboxImage.draw(self, renderer, *args, **kwargs)
93+
94+
95+
if 1:
96+
from matplotlib.transforms import Bbox, TransformedBbox
97+
from matplotlib.ticker import ScalarFormatter
98+
99+
fig = plt.gcf()
100+
fig.clf()
101+
ax = plt.subplot(111)
102+
103+
years = np.arange(2004, 2009)
104+
box_colors = [(0.8, 0.2, 0.2),
105+
(0.2, 0.8, 0.2),
106+
(0.2, 0.2, 0.8),
107+
(0.7, 0.5, 0.8),
108+
(0.3, 0.8, 0.7),
109+
]
110+
heights = np.random.random(years.shape) * 7000 + 3000
111+
112+
fmt = ScalarFormatter(useOffset=False)
113+
ax.xaxis.set_major_formatter(fmt)
114+
115+
for year, h, bc in zip(years, heights, box_colors):
116+
bbox0 = Bbox.from_extents(year-0.4, 0., year+0.4, h)
117+
bbox = TransformedBbox(bbox0, ax.transData)
118+
rb_patch = RibbonBoxImage(bbox, bc)
119+
120+
ax.add_artist(rb_patch)
121+
122+
ax.annotate(r"%d" % (int(h/100.)*100),
123+
(year, h), va="bottom", ha="center")
124+
125+
patch_gradient = BboxImage(ax.bbox,
126+
interpolation="bicubic",
127+
zorder=0.1,
128+
)
129+
gradient = np.zeros((2, 2, 4), dtype=np.float)
130+
gradient[:,:,:3] = [1, 1, 0.]
131+
gradient[:,:,3] = [[0.1, 0.3],[0.3, 0.5]] # alpha channel
132+
patch_gradient.set_array(gradient)
133+
ax.add_artist(patch_gradient)
134+
135+
136+
ax.set_xlim(years[0]-0.5, years[-1]+0.5)
137+
ax.set_ylim(0, 10000)
138+
139+
plt.show()
140+

lib/matplotlib/image.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
# the image namespace:
2525
from matplotlib._image import *
2626

27+
from matplotlib.transforms import BboxBase
28+
2729
class AxesImage(martist.Artist, cm.ScalarMappable):
2830
zorder = 1
2931
# map interpolation strings to module constants
@@ -744,6 +746,149 @@ def write_png(self, fname):
744746
rows, cols, buffer = im.as_rgba_str()
745747
_png.write_png(buffer, cols, rows, fname)
746748

749+
750+
class BboxImage(AxesImage):
751+
"""
752+
The Image class whose size is determined by the given bbox.
753+
"""
754+
zorder = 1
755+
def __init__(self, bbox,
756+
cmap = None,
757+
norm = None,
758+
interpolation=None,
759+
origin=None,
760+
filternorm=1,
761+
filterrad=4.0,
762+
resample = False,
763+
**kwargs
764+
):
765+
766+
"""
767+
cmap is a colors.Colormap instance
768+
norm is a colors.Normalize instance to map luminance to 0-1
769+
770+
kwargs are an optional list of Artist keyword args
771+
"""
772+
773+
AxesImage.__init__(self, ax=None,
774+
cmap = cmap,
775+
norm = norm,
776+
interpolation=interpolation,
777+
origin=origin,
778+
filternorm=filternorm,
779+
filterrad=filterrad,
780+
resample = resample,
781+
**kwargs
782+
)
783+
784+
self.bbox = bbox
785+
786+
def get_window_extent(self, renderer=None):
787+
if renderer is None:
788+
renderer = self.get_figure()._cachedRenderer
789+
790+
if isinstance(self.bbox, BboxBase):
791+
return self.bbox
792+
elif callable(self.bbox):
793+
return self.bbox(renderer)
794+
else:
795+
raise ValueError("unknown type of bbox")
796+
797+
798+
def contains(self, mouseevent):
799+
"""Test whether the mouse event occured within the image.
800+
"""
801+
802+
if callable(self._contains): return self._contains(self,mouseevent)
803+
804+
if not self.get_visible():# or self.get_figure()._renderer is None:
805+
return False,{}
806+
807+
x, y = mouseevent.x, mouseevent.y
808+
inside = self.get_window_extent().contains(x, y)
809+
810+
return inside,{}
811+
812+
def get_size(self):
813+
'Get the numrows, numcols of the input image'
814+
if self._A is None:
815+
raise RuntimeError('You must first set the image array')
816+
817+
return self._A.shape[:2]
818+
819+
def make_image(self, renderer, magnification=1.0):
820+
if self._A is None:
821+
raise RuntimeError('You must first set the image array or the image attribute')
822+
823+
if self._imcache is None:
824+
if self._A.dtype == np.uint8 and len(self._A.shape) == 3:
825+
im = _image.frombyte(self._A, 0)
826+
im.is_grayscale = False
827+
else:
828+
if self._rgbacache is None:
829+
x = self.to_rgba(self._A, self._alpha)
830+
self._rgbacache = x
831+
else:
832+
x = self._rgbacache
833+
im = _image.fromarray(x, 0)
834+
if len(self._A.shape) == 2:
835+
im.is_grayscale = self.cmap.is_gray()
836+
else:
837+
im.is_grayscale = False
838+
self._imcache = im
839+
840+
if self.origin=='upper':
841+
im.flipud_in()
842+
else:
843+
im = self._imcache
844+
845+
if 0:
846+
fc = self.axes.patch.get_facecolor()
847+
bg = mcolors.colorConverter.to_rgba(fc, 0)
848+
im.set_bg( *bg)
849+
850+
# image input dimensions
851+
im.reset_matrix()
852+
853+
im.set_interpolation(self._interpd[self._interpolation])
854+
855+
im.set_resample(self._resample)
856+
857+
l, b, r, t = self.get_window_extent(renderer).extents #bbox.extents
858+
widthDisplay = (round(r) + 0.5) - (round(l) - 0.5)
859+
heightDisplay = (round(t) + 0.5) - (round(b) - 0.5)
860+
widthDisplay *= magnification
861+
heightDisplay *= magnification
862+
#im.apply_translation(tx, ty)
863+
864+
numrows, numcols = self._A.shape[:2]
865+
866+
# resize viewport to display
867+
rx = widthDisplay / numcols
868+
ry = heightDisplay / numrows
869+
#im.apply_scaling(rx*sx, ry*sy)
870+
im.apply_scaling(rx, ry)
871+
#im.resize(int(widthDisplay+0.5), int(heightDisplay+0.5),
872+
# norm=self._filternorm, radius=self._filterrad)
873+
im.resize(int(widthDisplay), int(heightDisplay),
874+
norm=self._filternorm, radius=self._filterrad)
875+
return im
876+
877+
878+
@allow_rasterization
879+
def draw(self, renderer, *args, **kwargs):
880+
if not self.get_visible(): return
881+
# todo: we should be able to do some cacheing here
882+
image_mag = renderer.get_image_magnification()
883+
im = self.make_image(renderer, image_mag)
884+
l, b, r, t = self.get_window_extent(renderer).extents
885+
gc = renderer.new_gc()
886+
self._set_gc_clip(gc)
887+
#gc.set_clip_path(self.get_clip_path())
888+
renderer.draw_image(gc, round(l), round(b), im)
889+
890+
891+
747892
def imread(fname):
748893
"""
749894
Return image file in *fname* as :class:`numpy.array`.

0 commit comments

Comments
 (0)