diff --git a/doc/_static/ggplot.png b/doc/_static/ggplot.png new file mode 100644 index 000000000000..f103f2541b75 Binary files /dev/null and b/doc/_static/ggplot.png differ diff --git a/doc/_static/holoviews.png b/doc/_static/holoviews.png new file mode 100644 index 000000000000..f495d0e25737 Binary files /dev/null and b/doc/_static/holoviews.png differ diff --git a/doc/_static/seaborn.png b/doc/_static/seaborn.png new file mode 100644 index 000000000000..d1e815ef89b6 Binary files /dev/null and b/doc/_static/seaborn.png differ diff --git a/doc/_templates/index.html b/doc/_templates/index.html index 0343730ec5c1..35dfcfe04b6c 100644 --- a/doc/_templates/index.html +++ b/doc/_templates/index.html @@ -158,7 +158,11 @@

Toolkits

including a choice of two projection and mapping toolkits basemap and cartopy, 3d plotting with mplot3d, -axes and axis helpers in axes_grid and more. +axes and axis helpers in axes_grid, +several higher-level plotting interfaces + seaborn, + holoviews, + ggplot, and more.

Citing matplotlib

diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index 4bbd733786e6..46cdcecaa88d 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -161,8 +161,6 @@

{{ _('Navigation') }}

{% block relbar1 %} - - diff --git a/doc/conf.py b/doc/conf.py index ed1f2fd4d413..592b349ca104 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -213,6 +213,8 @@ # Output file base name for HTML help builder. htmlhelp_basename = 'Matplotlibdoc' +# Path to favicon +html_favicon = '_static/favicon.ico' # Options for LaTeX output # ------------------------ diff --git a/doc/mpl_toolkits/index.rst b/doc/mpl_toolkits/index.rst index ba3ae7efc305..a39c3905fe28 100644 --- a/doc/mpl_toolkits/index.rst +++ b/doc/mpl_toolkits/index.rst @@ -172,6 +172,26 @@ level interface for drawing statistical graphics with matplotlib. It aims to make visualization a central part of exploring and understanding complex datasets. +.. image:: /_static/seaborn.png + :height: 157px + +.. _toolkit_holoviews: + +holoviews +========= +(*Not distributed with matplotlib*) + +`holoviews `_ makes it easier to visualize data +interactively, especially in a `Jupyter notebook +`_, by providing a set of declarative +plotting objects that store your data and associated metadata. Your +data is then immediately visualizable alongside or overlaid with other +data, either statically or with automatically provided widgets for +parameter exploration. + +.. image:: /_static/holoviews.png + :height: 354px + .. _toolkit_ggplot: ggplot @@ -181,6 +201,9 @@ ggplot `ggplot `_ is a port of the R ggplot2 to python based on matplotlib. +.. image:: /_static/ggplot.png + :height: 195px + .. _toolkit_prettyplotlib: diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index c68fc0f0dbc0..d69549a7e2ad 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -3861,7 +3861,7 @@ def scatter(self, x, y, s=20, c=None, marker='o', cmap=None, norm=None, # favor of mapping, not rgb or rgba. try: c_array = np.asanyarray(c, dtype=float) - if c_array.size == x.size: + if c_array.size == x.size and c_array.ndim == 1: c = np.ma.ravel(c_array) else: # Wrong size; it must not be intended for mapping. diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 3af706325914..2b8b0e1b1e96 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -342,7 +342,7 @@ def _apply_params(self, **kw): # -> points. grab the integer from the `Text` object # instead of saving the string representation v = getattr(self.label1, 'get_' + k)() - setattr(self, '_' + k, v) + setattr(self, '_label' + k, v) class XTick(Tick): diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index f3a80f470d75..dcc0a1db6bd6 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -269,10 +269,6 @@ def to_rgba(self, x, alpha=None, bytes=False, norm=True): if norm: x = self.norm(x) rgba = self.cmap(x, alpha=alpha, bytes=bytes) - # For floating-point greyscale images, we treat negative as - # transparent so we copy that over to the alpha channel - if x.ndim == 2 and x.dtype.kind == 'f': - rgba[:, :, 3][x < 0.0] = 0 return rgba def set_array(self, A): diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 3bdf84ba1245..2a33ba21b374 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -510,7 +510,7 @@ def set_linestyle(self, ls): =========================== ================= ``'-'`` or ``'solid'`` solid line ``'--'`` or ``'dashed'`` dashed line - ``'-.'`` or ``'dash_dot'`` dash-dotted line + ``'-.'`` or ``'dashdot'`` dash-dotted line ``':'`` or ``'dotted'`` dotted line =========================== ================= diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index ade8bd8a28fe..a29e62cc78a7 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -354,20 +354,22 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, out_height = int(out_height_base) if not unsampled: + created_rgba_mask = False + if A.ndim == 2: A = self.norm(A) + # If the image is greyscale, convert to RGBA with the + # correct alpha channel for resizing + rgba = np.empty((A.shape[0], A.shape[1], 4), dtype=A.dtype) + rgba[..., 0:3] = np.expand_dims(A, 2) if A.dtype.kind == 'f': - # For floating-point greyscale images, we treat negative - # numbers as transparent. - - # TODO: Use np.full when we support Numpy 1.9 as a - # minimum - output = np.empty((out_height, out_width), dtype=A.dtype) - output[...] = -100.0 + rgba[..., 3] = ~A.mask else: - output = np.zeros((out_height, out_width), dtype=A.dtype) - + rgba[..., 3] = np.where(A.mask, 0, np.iinfo(A.dtype).max) + A = rgba + output = np.zeros((out_height, out_width, 4), dtype=A.dtype) alpha = 1.0 + created_rgba_mask = True elif A.ndim == 3: # Always convert to RGBA, even if only RGB input if A.shape[2] == 3: @@ -388,10 +390,16 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, self.get_resample(), alpha, self.get_filternorm() or 0.0, self.get_filterrad() or 0.0) + if created_rgba_mask: + # Convert back to a masked greyscale array so + # colormapping works correctly + output = np.ma.masked_array( + output[..., 0], output[..., 3] < 0.5) + output = self.to_rgba(output, bytes=True, norm=False) - # Apply alpha *after* if the input was greyscale - if A.ndim == 2: + # Apply alpha *after* if the input was greyscale without a mask + if A.ndim == 2 or created_rgba_mask: alpha = self.get_alpha() if alpha is not None and alpha != 1.0: alpha_channel = output[:, :, 3] diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 4f18d0526e6f..3af482cf6033 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -737,6 +737,7 @@ def _auto_legend_data(self): ax = self.parent bboxes = [] lines = [] + offsets = [] for handle in ax.lines: assert isinstance(handle, Line2D) @@ -755,12 +756,19 @@ def _auto_legend_data(self): transform = handle.get_transform() bboxes.append(handle.get_path().get_extents(transform)) + for handle in ax.collections: + transform, transOffset, hoffsets, paths = handle._prepare_points() + + if len(hoffsets): + for offset in transOffset.transform(hoffsets): + offsets.append(offset) + try: vertices = np.concatenate([l.vertices for l in lines]) except ValueError: vertices = np.array([]) - return [vertices, bboxes, lines] + return [vertices, bboxes, lines, offsets] def draw_frame(self, b): 'b is a boolean. Set draw frame to b' @@ -920,7 +928,7 @@ def _find_best_position(self, width, height, renderer, consider=None): # should always hold because function is only called internally assert self.isaxes - verts, bboxes, lines = self._auto_legend_data() + verts, bboxes, lines, offsets = self._auto_legend_data() bbox = Bbox.from_bounds(0, 0, width, height) if consider is None: @@ -939,6 +947,7 @@ def _find_best_position(self, width, height, renderer, consider=None): # take their into account when checking vertex overlaps in # the next line. badness = legendBox.count_contains(verts) + badness += legendBox.count_contains(offsets) badness += legendBox.count_overlaps(bboxes) for line in lines: # FIXME: the following line is ill-suited for lines diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 2118bbc7e8ce..70e892fcdbdb 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -1012,7 +1012,7 @@ def set_linestyle(self, ls): =========================== ================= ``'-'`` or ``'solid'`` solid line ``'--'`` or ``'dashed'`` dashed line - ``'-.'`` or ``'dash_dot'`` dash-dotted line + ``'-.'`` or ``'dashdot'`` dash-dotted line ``':'`` or ``'dotted'`` dotted line ``'None'`` draw nothing ``' '`` draw nothing diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 1eee2088a490..b224f89b0619 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -68,13 +68,17 @@ ############################################################################## # FONTS -def get_unicode_index(symbol): - """get_unicode_index(symbol) -> integer +def get_unicode_index(symbol, math=True): + """get_unicode_index(symbol, [bool]) -> integer Return the integer index (from the Unicode table) of symbol. *symbol* can be a single unicode character, a TeX command (i.e. r'\pi'), or a Type1 symbol name (i.e. 'phi'). +If math is False, the current symbol should be treated as a non-math symbol. """ + # for a non-math symbol, simply return its unicode index + if not math: + return ord(symbol) # From UTF #25: U+2212 minus sign is the preferred # representation of the unary and binary minus sign rather than # the ASCII-derived U+002D hyphen-minus, because minus sign is @@ -438,7 +442,7 @@ def get_kern(self, font1, fontclass1, sym1, fontsize1, """ return 0. - def get_metrics(self, font, font_class, sym, fontsize, dpi): + def get_metrics(self, font, font_class, sym, fontsize, dpi, math=True): """ *font*: one of the TeX font names:: @@ -452,6 +456,8 @@ def get_metrics(self, font, font_class, sym, fontsize, dpi): *dpi*: current dots-per-inch + *math*: whether sym is a math character + Returns an object with the following attributes: - *advance*: The advance distance (in points) of the glyph. @@ -466,7 +472,7 @@ def get_metrics(self, font, font_class, sym, fontsize, dpi): the glyph. This corresponds to TeX's definition of "height". """ - info = self._get_info(font, font_class, sym, fontsize, dpi) + info = self._get_info(font, font_class, sym, fontsize, dpi, math) return info.metrics def set_canvas_size(self, w, h, d): @@ -582,14 +588,14 @@ def _get_offset(self, font, glyph, fontsize, dpi): return ((glyph.height/64.0/2.0) + (fontsize/3.0 * dpi/72.0)) return 0. - def _get_info(self, fontname, font_class, sym, fontsize, dpi): + def _get_info(self, fontname, font_class, sym, fontsize, dpi, math=True): key = fontname, font_class, sym, fontsize, dpi bunch = self.glyphd.get(key) if bunch is not None: return bunch font, num, symbol_name, fontsize, slanted = \ - self._get_glyph(fontname, font_class, sym, fontsize) + self._get_glyph(fontname, font_class, sym, fontsize, math) font.set_size(fontsize, dpi) glyph = font.load_char( @@ -679,7 +685,7 @@ def __init__(self, *args, **kwargs): _slanted_symbols = set(r"\int \oint".split()) - def _get_glyph(self, fontname, font_class, sym, fontsize): + def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): symbol_name = None font = None if fontname in self.fontmap and sym in latex_to_bakoma: @@ -699,7 +705,7 @@ def _get_glyph(self, fontname, font_class, sym, fontsize): if symbol_name is None: return self._stix_fallback._get_glyph( - fontname, font_class, sym, fontsize) + fontname, font_class, sym, fontsize, math) return font, num, symbol_name, fontsize, slanted @@ -796,7 +802,7 @@ def __init__(self, *args, **kwargs): def _map_virtual_font(self, fontname, font_class, uniindex): return fontname, uniindex - def _get_glyph(self, fontname, font_class, sym, fontsize): + def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): found_symbol = False if self.use_cmex: @@ -807,7 +813,7 @@ def _get_glyph(self, fontname, font_class, sym, fontsize): if not found_symbol: try: - uniindex = get_unicode_index(sym) + uniindex = get_unicode_index(sym, math) found_symbol = True except ValueError: uniindex = ord('?') @@ -901,11 +907,11 @@ def __init__(self, *args, **kwargs): self.fontmap[key] = fullpath self.fontmap[name] = fullpath - def _get_glyph(self, fontname, font_class, sym, fontsize): + def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): """ Override prime symbol to use Bakoma """ if sym == r'\prime': return self.bakoma._get_glyph(fontname, - font_class, sym, fontsize) + font_class, sym, fontsize, math) else: # check whether the glyph is available in the display font uniindex = get_unicode_index(sym) @@ -914,10 +920,10 @@ def _get_glyph(self, fontname, font_class, sym, fontsize): glyphindex = font.get_char_index(uniindex) if glyphindex != 0: return super(DejaVuFonts, self)._get_glyph('ex', - font_class, sym, fontsize) + font_class, sym, fontsize, math) # otherwise return regular glyph return super(DejaVuFonts, self)._get_glyph(fontname, - font_class, sym, fontsize) + font_class, sym, fontsize, math) class DejaVuSerifFonts(DejaVuFonts): @@ -1123,7 +1129,7 @@ def _get_font(self, font): self.fonts[cached_font.get_fontname()] = cached_font return cached_font - def _get_info (self, fontname, font_class, sym, fontsize, dpi): + def _get_info (self, fontname, font_class, sym, fontsize, dpi, math=True): 'load the cmfont, metrics and glyph with caching' key = fontname, sym, fontsize, dpi tup = self.glyphd.get(key) @@ -1449,7 +1455,7 @@ class Char(Node): from width) must be converted into a :class:`Kern` node when the :class:`Char` is added to its parent :class:`Hlist`. """ - def __init__(self, c, state): + def __init__(self, c, state, math=True): Node.__init__(self) self.c = c self.font_output = state.font_output @@ -1457,6 +1463,7 @@ def __init__(self, c, state): self.font_class = state.font_class self.fontsize = state.fontsize self.dpi = state.dpi + self.math = math # The real width, height and depth will be set during the # pack phase, after we know the real fontsize self._update_metrics() @@ -1466,7 +1473,7 @@ def __internal_repr__(self): def _update_metrics(self): metrics = self._metrics = self.font_output.get_metrics( - self.font, self.font_class, self.c, self.fontsize, self.dpi) + self.font, self.font_class, self.c, self.fontsize, self.dpi, self.math) if self.c == ' ': self.width = metrics.advance else: @@ -2580,7 +2587,7 @@ def math(self, s, loc, toks): def non_math(self, s, loc, toks): #~ print "non_math", toks s = toks[0].replace(r'\$', '$') - symbols = [Char(c, self.get_state()) for c in s] + symbols = [Char(c, self.get_state(), math=False) for c in s] hlist = Hlist(symbols) # We're going into math now, so set font to 'it' self.push_state() diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index d864ccf32770..87c2e24d1a8a 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -370,7 +370,7 @@ def set_linestyle(self, ls): =========================== ================= ``'-'`` or ``'solid'`` solid line ``'--'`` or ``'dashed'`` dashed line - ``'-.'`` or ``'dash_dot'`` dash-dotted line + ``'-.'`` or ``'dashdot'`` dash-dotted line ``':'`` or ``'dotted'`` dotted line =========================== ================= diff --git a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg index 3f7c4c2a57ce..eb1c1194c131 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg @@ -27,8 +27,7 @@ z " style="fill:#ffffff;"/> - +" id="mdc24d94838" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="m110d6fc078" style="stroke:#000000;stroke-width:0.5;"/> - + - + - - - + + + - + - + @@ -207,21 +206,21 @@ L 12.40625 0 z " id="DejaVuSans-31"/> - - - + + + - + - + @@ -251,9 +250,9 @@ Q 44.1875 33.984375 37.640625 27.21875 Q 31.109375 20.453125 19.1875 8.296875 " id="DejaVuSans-32"/> - - - + + + @@ -262,176 +261,176 @@ Q 31.109375 20.453125 19.1875 8.296875 +" id="md652217826" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="m85d89dbb30" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -442,37 +441,25 @@ L 0 2 +" id="m0525a49047" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="m60671aa7ca" style="stroke:#000000;stroke-width:0.5;"/> - + - - + + - - + + - - + + - + - + - - + + - + - + - + - - + + - + @@ -554,104 +553,104 @@ z +" id="mbe24b9f137" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="m7965eaa9d8" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -659,8 +658,8 @@ L -2 0 - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf b/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf new file mode 100644 index 000000000000..695b149f03dd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.png b/lib/matplotlib/tests/baseline_images/test_image/mask_image.png new file mode 100644 index 000000000000..1e4f2873e39f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg new file mode 100644 index 000000000000..174c5942c2ca --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png index fd72f2a9bff1..cb1853ed179a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png and b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter.png b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter.png new file mode 100644 index 000000000000..4e9b72e640ce Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter_transform.png b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter_transform.png new file mode 100644 index 000000000000..e2a90732fc11 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter_transform.png differ diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 780584d2e634..cc71df7c2d7d 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -4330,6 +4330,17 @@ def test_pandas_indexing_hist(): fig, axes = plt.subplots() axes.hist(ser_2) +@cleanup +def test_axis_set_tick_params_labelsize_labelcolor(): + # Tests fix for issue 4346 + axis_1 = plt.subplot() + axis_1.yaxis.set_tick_params(labelsize=30, labelcolor='red', direction='out') + + # Expected values after setting the ticks + assert axis_1.yaxis.majorTicks[0]._size == 4.0 + assert axis_1.yaxis.majorTicks[0]._color == 'k' + assert axis_1.yaxis.majorTicks[0]._labelsize == 30.0 + assert axis_1.yaxis.majorTicks[0]._labelcolor == 'red' if __name__ == '__main__': import nose diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 252c5248a68d..6af9a5ef5f12 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -610,6 +610,25 @@ def test_image_preserve_size2(): np.identity(n, bool)[::-1]) +@image_comparison(baseline_images=['mask_image'], + remove_text=True) +def test_mask_image(): + # Test mask image two ways: Using nans and using a masked array. + + fig, (ax1, ax2) = plt.subplots(1, 2) + + A = np.ones((5, 5)) + A[1:2, 1:2] = np.nan + + ax1.imshow(A, interpolation='nearest') + + A = np.zeros((5, 5), dtype=np.bool) + A[1:2, 1:2] = True + A = np.ma.masked_array(np.ones((5, 5), dtype=np.uint16), A) + + ax2.imshow(A, interpolation='nearest') + + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index a43231b964ee..293c64a3dbf5 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -16,6 +16,7 @@ import matplotlib.pyplot as plt import matplotlib as mpl import matplotlib.patches as mpatches +import matplotlib.transforms as mtrans @image_comparison(baseline_images=['legend_auto1'], remove_text=True) @@ -261,6 +262,32 @@ def test_nanscatter(): ax.grid(True) +@image_comparison(baseline_images=['not_covering_scatter'], extensions=['png']) +def test_not_covering_scatter(): + colors = ['b','g','r'] + + for n in range(3): + plt.scatter([n,], [n,], color=colors[n]) + + plt.legend(['foo', 'foo', 'foo'], loc='best') + plt.gca().set_xlim(-0.5, 2.2) + plt.gca().set_ylim(-0.5, 2.2) + + +@image_comparison(baseline_images=['not_covering_scatter_transform'], + extensions=['png']) +def test_not_covering_scatter_transform(): + # Offsets point to top left, the default auto position + offset = mtrans.Affine2D().translate(-20, 20) + x = np.linspace(0, 30, 1000) + plt.plot(x, x) + + plt.scatter([20], [10], transform=offset + plt.gca().transData) + + plt.legend(['foo', 'bar'], loc='best') + + if __name__ == '__main__': import nose nose.runmodule(argv=['-s', '--with-doctest'], exit=False) + diff --git a/src/_image_resample.h b/src/_image_resample.h index 3bf7aa182fba..cee102244f2e 100644 --- a/src/_image_resample.h +++ b/src/_image_resample.h @@ -533,6 +533,35 @@ template <> class type_mapping }; +template <> class type_mapping +{ + public: + typedef agg::rgba16 color_type; + typedef fixed_blender_rgba_plain blender_type; + typedef fixed_blender_rgba_pre pre_blender_type; + typedef agg::pixfmt_alpha_blend_rgba pixfmt_type; + typedef agg::pixfmt_alpha_blend_rgba pixfmt_pre_type; + + template + struct span_gen_affine_type + { + typedef agg::span_image_resample_rgba_affine type; + }; + + template + struct span_gen_filter_type + { + typedef agg::span_image_filter_rgba type; + }; + + template + struct span_gen_nn_type + { + typedef agg::span_image_filter_rgba_nn type; + }; +}; + + template <> class type_mapping { public: diff --git a/src/_image_wrapper.cpp b/src/_image_wrapper.cpp index dac7c44e2ad8..aac86bf93673 100644 --- a/src/_image_wrapper.cpp +++ b/src/_image_wrapper.cpp @@ -226,6 +226,19 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs) params); Py_END_ALLOW_THREADS break; + case NPY_UINT16: + case NPY_INT16: + Py_BEGIN_ALLOW_THREADS + resample( + (agg::rgba16 *)PyArray_DATA(input_array), + PyArray_DIM(input_array, 1), + PyArray_DIM(input_array, 0), + (agg::rgba16 *)PyArray_DATA(output_array), + PyArray_DIM(output_array, 1), + PyArray_DIM(output_array, 0), + params); + Py_END_ALLOW_THREADS + break; case NPY_FLOAT32: Py_BEGIN_ALLOW_THREADS resample( @@ -254,13 +267,13 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs) PyErr_SetString( PyExc_ValueError, "3-dimensional arrays must be of dtype unsigned byte, " - "float32 or float64"); + "unsigned short, float32 or float64"); goto error; } } else { PyErr_Format( PyExc_ValueError, - "If 3-dimensional, array must be RGBA. Got %d.", + "If 3-dimensional, array must be RGBA. Got %d planes.", PyArray_DIM(input_array, 2)); goto error; }