From efd1c4b244c9f85d130590eb0f2c8f7fb979cc71 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Tue, 10 May 2011 01:11:46 +0900 Subject: [PATCH 001/214] textpath tries the adobe standard encoding as a default for fonts --- lib/matplotlib/textpath.py | 45 +++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index 943113fc757e..4a22409efd6a 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -12,6 +12,8 @@ import numpy as np +import warnings + class TextToPath(object): """ A class that convert a given text to a path using ttf fonts. @@ -32,6 +34,14 @@ def __init__(self): self._texmanager = None + self._adobe_standard_encoding = self._get_adobe_standard_encoding() + + + def _get_adobe_standard_encoding(self): + enc_name = dviread.find_tex_file('8a.enc') + enc = dviread.Encoding(enc_name) + return dict([(c, i) for i, c in enumerate(enc.encoding)]) + def _get_font(self, prop): """ find a ttf font. @@ -312,14 +322,25 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, if font_and_encoding is None: font_bunch = self.tex_font_map[dvifont.texname] font = FT2Font(str(font_bunch.filename)) - try: - font.select_charmap(1094992451) # select ADOBE_CUSTOM - except ValueError: - font.set_charmap(0) - if font_bunch.encoding: - enc = dviread.Encoding(font_bunch.encoding) + + for charmap_name, charmap_code in [("ADOBE_CUSTOM", 1094992451), + ("ADOBE_STANDARD", 1094995778)]: + try: + font.select_charmap(charmap_code) + except ValueError: + pass + else: + break else: - enc = None + charmap_name = "" + warnings.warn("No supported encoding in font (%s)." % font_bunch.filename) + + if charmap_name == "ADOBE_STANDARD" and font_bunch.encoding: + enc0 = dviread.Encoding(font_bunch.encoding) + enc = dict([(i, self._adobe_standard_encoding.get(c, None)) \ + for i, c in enumerate(enc0.encoding)]) + else: + enc = dict() self._ps_fontd[dvifont.texname] = font, enc else: @@ -332,11 +353,19 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, if not char_id in glyph_map: font.clear() font.set_size(self.FONT_SCALE, self.DPI) + if enc: charcode = enc.get(glyph, None) + else: charcode = glyph - glyph0 = font.load_char(glyph, flags=ft2font_flag) + if charcode: + glyph0 = font.load_char(charcode, flags=ft2font_flag) + else: + warnings.warn("The glyph (%d) of font (%s) cannot be converted with the encoding. Glyph may be wrong" % (glyph, font_bunch.filename)) + + glyph0 = font.load_char(glyph, flags=ft2font_flag) glyph_map_new[char_id] = self.glyph_to_path(glyph0) + glyph_ids.append(char_id) xpositions.append(x1) ypositions.append(y1) From 2910319053566f33284c4e5954e2837799d3d643 Mon Sep 17 00:00:00 2001 From: butterw Date: Fri, 17 Jun 2011 22:46:59 +0200 Subject: [PATCH 002/214] Named figures feature: plt.figure("today") --- lib/matplotlib/__init__.py | 1 + lib/matplotlib/pyplot.py | 36 +- .../test_figure/figure_today.pdf | Bin 0 -> 7050 bytes .../test_figure/figure_today.png | Bin 0 -> 23689 bytes .../test_figure/figure_today.svg | 364 ++++++++++++++++++ lib/matplotlib/tests/test_figure.py | 37 ++ 6 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_figure/figure_today.png create mode 100644 lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg create mode 100644 lib/matplotlib/tests/test_figure.py diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index dde90f8f03ef..a9859f8c97ea 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -964,6 +964,7 @@ def tk_window_focus(): 'matplotlib.tests.test_mlab', 'matplotlib.tests.test_transforms', 'matplotlib.tests.test_axes', + 'matplotlib.tests.test_figure', 'matplotlib.tests.test_dates', 'matplotlib.tests.test_spines', 'matplotlib.tests.test_image', diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index e68ed2515239..0c1575990ff4 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -217,6 +217,14 @@ def figure(num=None, # autoincrement if None, else integer from 1-N figure(1) + The same applies if *num* is a string. In this case *num* will be used + as an explicit figure label:: + + figure("today") + + and in windowed backends, the window title will be set to this figure + label. + If you are creating many figures, make sure you explicitly call "close" on the figures you are not using, because this will enable pylab to properly clean up the memory. @@ -247,16 +255,26 @@ class that will be passed on to :meth:`new_figure_manager` in the if facecolor is None : facecolor = rcParams['figure.facecolor'] if edgecolor is None : edgecolor = rcParams['figure.edgecolor'] + allnums = get_fignums() + figLabel = '' if num is None: - allnums = [f.num for f in _pylab_helpers.Gcf.get_all_fig_managers()] if allnums: num = max(allnums) + 1 else: num = 1 + elif is_string_like(num): + figLabel = num + allLabels = get_figlabels() + if figLabel not in allLabels: + if len(allLabels): + num = max(allnums) + 1 + else: + num = 1 + else: + num = allLabels.index(figLabel) + 1 # matlab style num else: num = int(num) # crude validation of num argument - figManager = _pylab_helpers.Gcf.get_fig_manager(num) if figManager is None: if get_backend().lower() == 'ps': dpi = 72 @@ -269,6 +287,10 @@ class that will be passed on to :meth:`new_figure_manager` in the FigureClass=FigureClass, **kwargs) + if figLabel: + figManager.set_window_title(figLabel) + figManager.canvas.figure.set_label(figLabel) + # make this figure current on button press event def make_active(event): _pylab_helpers.Gcf.set_active(figManager) @@ -299,6 +321,11 @@ def get_fignums(): fignums.sort() return fignums +def get_figlabels(): + "Return a list of existing figure labels." + figManagers = _pylab_helpers.Gcf.get_all_fig_managers() + return [m.canvas.figure.get_label() for m in figManagers] + def get_current_fig_manager(): figManager = _pylab_helpers.Gcf.get_active() if figManager is None: @@ -338,6 +365,11 @@ def close(*args): _pylab_helpers.Gcf.destroy_all() elif isinstance(arg, int): _pylab_helpers.Gcf.destroy(arg) + elif is_string_like(arg): + allLabels = get_figlabels() + if arg in allLabels: + num = get_fignums()[allLabels.index(arg)] + _pylab_helpers.Gcf.destroy(num) elif isinstance(arg, Figure): _pylab_helpers.Gcf.destroy_fig(arg) else: diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9fea07616a4128a6fbdcf9c194aa4391fe747a2d GIT binary patch literal 7050 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg new file mode 100644 index 000000000000..55fa803f32da --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py new file mode 100644 index 000000000000..a7cb397d2f43 --- /dev/null +++ b/lib/matplotlib/tests/test_figure.py @@ -0,0 +1,37 @@ +import matplotlib +from nose.tools import assert_equal +from matplotlib.testing.decorators import image_comparison, knownfailureif +import matplotlib.pyplot as plt + + +def test_figure_label(): + # pyplot figure creation, selection and closing with figure label and number + plt.close('all') + plt.figure('today') + plt.figure(3) + plt.figure('tomorow') + plt.figure() + plt.figure(0) + plt.figure(1) + plt.figure(3) + assert_equal(plt.get_fignums(), [0, 1, 3, 4, 5]) + assert_equal(plt.get_figlabels(), ['', 'today', '', 'tomorow', '']) + plt.close(10) + plt.close() + plt.close(5) + plt.close('tomorow') + assert_equal(plt.get_fignums(), [0, 1]) + assert_equal(plt.get_figlabels(), ['', 'today']) + + +@image_comparison(baseline_images=['figure_today']) +def test_figure(): + # named figure support + fig = plt.figure('today') + ax = fig.add_subplot(111) + ax.set_title(fig.get_label()) + ax.plot(range(5)) + fig = plt.figure('tomorow') + plt.plot([0], 'or') + fig = plt.figure('today') + fig.savefig('figure_today') From ca42eaaf6ad63eb831d0c2212e2d4ae779a46dc3 Mon Sep 17 00:00:00 2001 From: butterw Date: Mon, 20 Jun 2011 06:50:35 +0200 Subject: [PATCH 003/214] named figures bugfix --- lib/matplotlib/pyplot.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 0c1575990ff4..1b8f5fbb6db4 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -271,7 +271,8 @@ class that will be passed on to :meth:`new_figure_manager` in the else: num = 1 else: - num = allLabels.index(figLabel) + 1 # matlab style num + inum = allLabels.index(figLabel) + num = allnums[inum] else: num = int(num) # crude validation of num argument @@ -324,6 +325,7 @@ def get_fignums(): def get_figlabels(): "Return a list of existing figure labels." figManagers = _pylab_helpers.Gcf.get_all_fig_managers() + figManagers.sort(key=lambda m: m.num) return [m.canvas.figure.get_label() for m in figManagers] def get_current_fig_manager(): @@ -347,9 +349,11 @@ def close(*args): ``close()`` by itself closes the current figure + ``close(h)`` where *h* is a :class:`Figure` instance, closes that figure + ``close(num)`` closes figure number *num* - ``close(h)`` where *h* is a :class:`Figure` instance, closes that figure + ``close(name)`` where *name* is a string, closes figure with that label ``close('all')`` closes all the figure windows """ From 4d451602b87090947e7b6cde503acfa8d0bd3655 Mon Sep 17 00:00:00 2001 From: butterw Date: Mon, 20 Jun 2011 20:49:39 +0200 Subject: [PATCH 004/214] warning on figure('all') creation --- lib/matplotlib/pyplot.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 1b8f5fbb6db4..705f947f384e 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -14,7 +14,7 @@ """ -import sys +import sys, warnings import matplotlib from matplotlib import _pylab_helpers, interactive @@ -266,6 +266,8 @@ class that will be passed on to :meth:`new_figure_manager` in the figLabel = num allLabels = get_figlabels() if figLabel not in allLabels: + if figLabel == 'all': + warnings.warn("close('all') closes all existing figures") if len(allLabels): num = max(allnums) + 1 else: From 32293edf29bed8ffc74ede12b648dd9b37bae903 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 22 Jun 2011 14:21:52 -0400 Subject: [PATCH 005/214] Add axes.labelweight rcParam. Closes #332. --- lib/matplotlib/axis.py | 6 ++++-- lib/matplotlib/rcsetup.py | 1 + lib/mpl_toolkits/axisartist/axis_artist.py | 12 +++++++++--- matplotlibrc.template | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index ab9036289f41..7e929d888b86 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1552,7 +1552,8 @@ def _get_label(self): # time by _update_label_positions) label = mtext.Text(x=0.5, y=0, fontproperties = font_manager.FontProperties( - size=rcParams['axes.labelsize']), + size=rcParams['axes.labelsize'], + weight=rcParams['axes.labelweight']), color = rcParams['axes.labelcolor'], verticalalignment='top', horizontalalignment='center', @@ -1809,7 +1810,8 @@ def _get_label(self): label = mtext.Text(x=0, y=0.5, # todo: get the label position fontproperties=font_manager.FontProperties( - size=rcParams['axes.labelsize']), + size=rcParams['axes.labelsize'], + weight=rcParams['axes.labelweight']), color = rcParams['axes.labelcolor'], verticalalignment='center', horizontalalignment='right', diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index b2ee183ae5f9..ddcf65cfcfd3 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -441,6 +441,7 @@ def __call__(self, s): 'axes.titlesize' : ['large', validate_fontsize], # fontsize of the axes title 'axes.grid' : [False, validate_bool], # display grid or not 'axes.labelsize' : ['medium', validate_fontsize], # fontsize of the x any y labels + 'axes.labelweight' : ['normal', str], # fontsize of the x any y labels 'axes.labelcolor' : ['k', validate_color], # color of axis label 'axes.formatter.limits' : [[-7, 7], validate_nseq_int(2)], # use scientific notation if log10 diff --git a/lib/mpl_toolkits/axisartist/axis_artist.py b/lib/mpl_toolkits/axisartist/axis_artist.py index cce0639a5bc4..59239f6a0b01 100644 --- a/lib/mpl_toolkits/axisartist/axis_artist.py +++ b/lib/mpl_toolkits/axisartist/axis_artist.py @@ -1381,7 +1381,9 @@ def _init_label(self, **kw): rcParams['axes.labelsize']) #labelcolor = kw.get("labelcolor", # rcParams['axes.labelcolor']) - fontprops = font_manager.FontProperties(size=labelsize) + fontprops = font_manager.FontProperties( + size=labelsize, + weight=rcParams['axes.labelweight']) textprops = dict(fontproperties = fontprops) #color = labelcolor) @@ -1407,7 +1409,9 @@ def _update_label(self, renderer): if not self.label.get_visible(): return - fontprops = font_manager.FontProperties(size=rcParams['axes.labelsize']) + fontprops = font_manager.FontProperties( + size=rcParams['axes.labelsize'], + weight=rcParams['axes.labelweight']) #pad_points = self.major_tick_pad @@ -1450,7 +1454,9 @@ def _draw_label2(self, renderer): if not self.label.get_visible(): return - fontprops = font_manager.FontProperties(size=rcParams['axes.labelsize']) + fontprops = font_manager.FontProperties( + size=rcParams['axes.labelsize'], + weight=rcParams['axes.labelweight']) #pad_points = self.major_tick_pad diff --git a/matplotlibrc.template b/matplotlibrc.template index ff41e2fc0119..0b76e55b2a45 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -194,6 +194,7 @@ backend : %(backend)s #axes.grid : False # display grid or not #axes.titlesize : large # fontsize of the axes title #axes.labelsize : medium # fontsize of the x any y labels +#axes.labelweight : normal # weight of the x and y labels #axes.labelcolor : black #axes.axisbelow : False # whether axis gridlines and ticks are below # the axes elements (lines, text, etc) From d5a20a194fc58485261ec86d81c40946d5ddaebe Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 22 Jun 2011 15:25:19 -0400 Subject: [PATCH 006/214] Add set_theta_offset, set_theta_direction and set_theta_zero_location to polar axes to control the location of 0 and directionality of theta. Closes #316. --- CHANGELOG | 4 + lib/matplotlib/projections/polar.py | 108 +- .../test_axes/polar_theta_position.pdf | Bin 0 -> 19727 bytes .../test_axes/polar_theta_position.png | Bin 0 -> 75626 bytes .../test_axes/polar_theta_position.svg | 1602 +++++++++++++++++ lib/matplotlib/tests/test_axes.py | 11 + 6 files changed, 1717 insertions(+), 8 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.png create mode 100644 lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg diff --git a/CHANGELOG b/CHANGELOG index 07eca61726bd..8e25c09afdce 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2011-06-22 Add set_theta_offset, set_theta_direction and + set_theta_zero_location to polar axes to control the + location of 0 and directionality of theta. - MGD + 2011-06-16 Added *bottom* keyword parameter for the stem command. Also, implemented a legend handler for the stem plot. - JJL diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index c3f9ea7f2e69..c4589040574a 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -36,22 +36,33 @@ class PolarTransform(Transform): output_dims = 2 is_separable = False - def __init__(self, axis=None): + def __init__(self, axis=None, use_rmin=True): Transform.__init__(self) self._axis = axis + self._use_rmin = use_rmin def transform(self, tr): xy = np.empty(tr.shape, np.float_) if self._axis is not None: - rmin = self._axis.viewLim.ymin + if self._use_rmin: + rmin = self._axis.viewLim.ymin + else: + rmin = 0 + theta_offset = self._axis.get_theta_offset() + theta_direction = self._axis.get_theta_direction() else: rmin = 0 + theta_offset = 0 + theta_direction = 1 t = tr[:, 0:1] r = tr[:, 1:2] x = xy[:, 0:1] y = xy[:, 1:2] + t *= theta_direction + t += theta_offset + if rmin != 0: r = r - rmin mask = r < 0 @@ -79,7 +90,7 @@ def transform_path(self, path): transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ def inverted(self): - return PolarAxes.InvertedPolarTransform(self._axis) + return PolarAxes.InvertedPolarTransform(self._axis, self._use_rmin) inverted.__doc__ = Transform.inverted.__doc__ class PolarAffine(Affine2DBase): @@ -121,23 +132,40 @@ class InvertedPolarTransform(Transform): output_dims = 2 is_separable = False - def __init__(self, axis=None): + def __init__(self, axis=None, use_rmin=True): Transform.__init__(self) self._axis = axis + self._use_rmin = use_rmin def transform(self, xy): + if self._axis is not None: + if self._use_rmin: + rmin = self._axis.viewLim.ymin + else: + rmin = 0 + theta_offset = self._axis.get_theta_offset() + theta_direction = self._axis.get_theta_direction() + else: + rmin = 0 + theta_offset = 0 + theta_direction = 1 + x = xy[:, 0:1] y = xy[:, 1:] r = np.sqrt(x*x + y*y) - if self._axis is not None: - r += self._axis.viewLim.ymin theta = np.arccos(x / r) theta = np.where(y < 0, 2 * np.pi - theta, theta) + + theta -= theta_offset + theta *= theta_direction + + r += rmin + return np.concatenate((theta, r), 1) transform.__doc__ = Transform.transform.__doc__ def inverted(self): - return PolarAxes.PolarTransform() + return PolarAxes.PolarTransform(self._axis, self._use_rmin) inverted.__doc__ = Transform.inverted.__doc__ class ThetaFormatter(Formatter): @@ -231,6 +259,9 @@ def cla(self): # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? + self.set_theta_offset(0) + self.set_theta_direction(1) + def _init_axis(self): "move this out of __init__ because non-separable axes don't use it" self.xaxis = maxis.XAxis(self) @@ -253,7 +284,7 @@ def _set_lim_and_transforms(self): self.transProjection = self.PolarTransform(self) # This one is not aware of rmin - self.transPureProjection = self.PolarTransform() + self.transPureProjection = self.PolarTransform(self, use_rmin=False) # An affine transformation on the data, generally to limit the # range of the axes @@ -346,6 +377,67 @@ def set_rmin(self, rmin): def get_rmin(self): return self.viewLim.ymin + def set_theta_offset(self, offset): + """ + Set the offset for the location of 0 in radians. + """ + self._theta_offset = offset + + def get_theta_offset(self): + """ + Get the offset for the location of 0 in radians. + """ + return self._theta_offset + + def set_theta_zero_location(self, loc): + """ + Sets the location of theta's zero. (Calls set_theta_offset + with the correct value in radians under the hood.) + + May be one of "N", "NW", "W", "SW", "S", "SE", "E", or "NE". + """ + mapping = { + 'N': np.pi * 0.5, + 'NW': np.pi * 0.75, + 'W': np.pi, + 'SW': np.pi * 1.25, + 'S': np.pi * 1.5, + 'SE': np.pi * 1.75, + 'E': 0, + 'NE': np.pi * 0.25 } + return self.set_theta_offset(mapping[loc]) + + def set_theta_direction(self, direction): + """ + Set the direction in which theta increases. + + clockwise, -1: + Theta increases in the clockwise direction + + counterclockwise, anticlockwise, 1: + Theta increases in the counterclockwise direction + """ + if direction in ('clockwise',): + self._direction = -1 + elif direction in ('counterclockwise', 'anticlockwise'): + self._direction = 1 + elif direction in (1, -1): + self._direction = direction + else: + raise ValueError("direction must be 1, -1, clockwise or counterclockwise") + + def get_theta_direction(self): + """ + Get the direction in which theta increases. + + -1: + Theta increases in the clockwise direction + + 1: + Theta increases in the counterclockwise direction + """ + return self._direction + def set_rlim(self, *args, **kwargs): if 'rmin' in kwargs: kwargs['ymin'] = kwargs.pop('rmin') diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5c41ec898c98838a02cafe59356c37d62a97dcc7 GIT binary patch literal 19727 zcmb@u1#lcqvOj3al7$vCj+j{*F*7qWGc&U+W=4ydnaQ%4nbBgjn5>h&Z}+{o_uqTB zad9zIlhxJPNtIpIJrVgMkrNW3VW4G(CaG8hl(#`M0O$d>1{TmmsA%j2(0msqB=Roa*v$z*CvN>NR^T60@E=qhpbelCc5@O{bkcV+1~C6EK+#O! z$lS&h0Q_6Lh^>tifa$OPf1ATV|32_f2L#_ajBT780qlQY@wY=CegNncj2&&A9Sq++ z`tU&E!##(0-oO2Wrjs@{GS?Tdb$hq=Lm~?+5WvjD_-@vJtNIZ7Pfa4`R`0F?=tQjE z?G-XMv^9EHA!Tf1>SP9B_=xFWA#-$cFxIz*cFR1=YLBMjbSU!X5l)Y<54n%v^qb@J zOy}vr2&~nJ{UU%1Quow&6Z+Jxw;(}U?~%if)Kn24$pnc~T~&8So=>KN$L-P!`R$9Q z#o4^a2+thav3x((Gn(i<(UEs=x4=bL(84!t3+%oj?hw0|$07Evk*U$XOBQ^B1y$I_ z$ZUg2(W*c5F;h37ofEV9kMEKn>N(#ubK2V+eRY2upDlG#QQV&B9*+XU3nr_oHAJ&K z4n|*J=u%fGrcT?8 z15e#1l9dp9-L=&kX|#=i-=+y!zMNeo2bvB(-Fq(=ySl-$zU)24b}!XXeAFA&PuiZ! z(!!Ia$s_o>9^b0X8?eCCxnhW-P`pNgb&HTZ$vPS`gWookFuhBj1mQh4bdL3h@=5V4 zy}jp`>PSrwkK|YdsSKUQU#->!Cc4Vyc?@ooSEc)A`MbAXh`+dme$frD;n_s{0dyW7YrTGj*0U=?{rR& zxuhg`O4KyR(wh67LU?pYfM!{R8Ewd{3ticm&QdHdaJ29&uS4(?&AXI+>3Yq(97``^ zp`%j(E+3UU{Elm0USYU);%*mJv5ckgXTZ^Qe=%+CJlP!2h|q zy%|7}wqr(*Pg_w;3GnvOZCfNc)lkp5ZB(;}dKzE$t_&nC6lcESA|xA1#CN^O?wJ&d$c)SNv_CJc4lWh6D3fz}3w#u@DRTX9@D zo{8gZwA`Z50IlNI@d_bt8Yv!=xL7cOs20YXHe0B&0m$t4eK7sC;G9MGo3rjLA~CB* z6{FjP!Q+Nwq^aX@JeCktwF#@!c$ZVhR~p@#I}iPXQd#~SQORJLV_&iH70V~N_SCY) z%OFrBrEPoUnalwEJUjl+HXXX_SN$+9A&sK;U<$&s`LrjkA;tLO*N*tbJI3D9xX{4| z^6TSI-71D0w?LR(4JiI=5@#Rrq3fye7{xOd!GJi9V=wC0crQqj)9dxNMWaE&`pw2A z1^ZXw8CL_HYDT1|04IuutC_=Z#rMd!za;~vL(p2BJ*x&$?JMuRZ&fv*>P{5z)KRPj`o3v0AfIbJ<&<&)kyYb0IZ=|=DxR=~P`<~LX) z+3&S0hJqF_@5^<%>lSNZ&NG<7KXHR94p=PluDz0kwS+-V*`vy_@GP1GLQ}f`ayiM~JlMVM{eV;7Xd+2AU5p zBZBY;5U2-DX6j!O?vRSZ$&a7=3lw*UG*)?{Wa3Z}3rwIAq-_0!5AW5nfKe(SkuRSh z2bJK=4fvj{Z|i*MjAuODrT*|e%(cb|)=!$IO+`8!Rxdj(x>i>=oAf2jbAFX278IFK z;;o;15(j1wmFo~wSqz?jqS<&ZY9$A{F@Tgp=PdrlW}FYdJnlAe{0>=x#AE!qE0aV- z8i+8z_#Nyd9$@bIWf_bat9AO%^n)<4Ucq_TUuk@06k#a&_>BbS3F?cs zL+^`*W2_W8DpAPJ(20B1e1*&)B|mFL>q7v7>=M~D&=VJ+6VSFW zvEQe>YwN6^6MefEEI+FB5r+xwF?K#EVhX9o4cgFI$rbkdbjWch^qgr&oy~$417zSmdkJp` z7s`Wx%}a-QqIWcp;Z$L(f$W&K|1k6%cF`6}R%lWgsk%q$5UNP6T&`15pp6NC69I-^095)|A;d8gvN3F~hPl1LPe$`GO|& zBua|DAl3c}<3vQGp6GE*14k4LOMpz?&Q7s{fg#R`4It$p!zPenCe=lzB~>RWjka11 zl9$IQwaKZY1I(|GbP*Wu=6I0$7%4gf8p%KcWZuj(#r`JqIimlA#r}#g3jvz z6T;Sa?#8M&B~OBKCskb(E-??{NX9m(QR5||yPr2u)^(?KQ1z)U7RquKn?}l_ z+}B{lVW(NXX^N_~d;xkM>kMNg#BLcG#O|=f<3oL8u=y%GV=nYvnCR<92$k;;PI7pQ z#heB*5s7#kjqr?8_GXHc_zKv>ajiWtMwezqKf9_Tl!Lli;|Xy)=&5U8oQTbM+) zTIrHx%hyuMK64r7yg*p<;QpR_Y zerJVdbR)DsoLMYk>0SoXISmezy6R^9!Z(;%6n)8&h`kws=#hC&XtZfL)L#`mF+HzHX;cuPhJ-!*NT|r_K3O0^ zQ&bZ{5-svCs8O01KaotI43h$BKM^+ll~elmq%}WeOdQcl<)*m> z;3FF+Eh94hUgmq|RH&|L4_B!LZ&Cd?n-J;B)(?xZ6XF=mgndXGr22MoVvY{k6S^OU zQQ8SvE0(r4PSL)E>VMut(6c_{XdY}Ltd=xh6}BZQ1KlKljShnK_$5`n9vf1zuW=xC z;ts0~Wih5%J89#$g6`RKx=f`ouX{|aU_UBM>=o~Gb?&Gn(}n|IODzl%8_g|Fw~A&H z(d4~k7c(A>s3g+^d8ol_pB3D0(tPsPqJq`aZ7!uWwe1KL0p$!gCZRjaQ@ReR(M7_% zcnb@Ubm^YzD4lPv-YyHsf(|~8P}W{-?h_O-LWkjErDr-_Y}wcEx;rprN#w&yioOvDiVk*?2zt%Y6Cml#F}FN9G@T<`U(JOllXQG1gAK;@{KhJ^7A-i>Xl)f}<5r6NW{b!tkbF(1;Ix7PPV_ z#zf%3usR#RN6VG+)2;bbfKv|J04D}MNyR{rSUrZ2T@$EQ+)FuG$RwUsB#1~nW8kzL z?B$~q0IE+`6Y!Z27EGFPI`7#alu;lHD?BN%!$6*5BB~Y)iWDSOr{2tFEe#)#ct15(u;5=6+(l z8YW*PCeTm?i7E-t4m5P&V@{vNM%~6ooS~Yahj) z{xzGc;7Zw(9lxCW>5Y#2U>1L73ISnF5wdJUn$0=W9zh%;M0iMVvXSF=B_xZK7P|1Q zw3k--rn?R#ICG>{jy;aFZBj?w0~SwLy_b4vg*&nWH-;KGRQR;!9ZOAQzec?VVNigm zUiQIvm-%8+D+zQK#wLzE`xVDp?koO_NsJ;yp|31@MQ*f#mFzRmyz3z2O+2bg7Cl3| zVWW%jS1df$^9$G!)S_P(Jf-u|VNy2|?LIM8A|j~G@FLD@)s)X4a=}V!quMSQFtjQV z7%=+Gn2Uu`m-h(N{hToiyXBDfb4NDdipmNOryI4bl2ar4lu_P!t#s02 zos|H)G!rqqFB6MK{Xyi$XLU6J*60k7R|?*IC}WUWe*pZkbCN4|;81DiwZv%{sAN$g z4kTm17782#2Z#x_1Ui~Hs$=~QL{p)76GTijl<{U7uC+t`E8At19df*jjQTGn8QS)3u=I$5uLN$Bp=4ySoZj=B;ONPBd(BQ?V@LalKw1|&_dX@9@^ABS(PA!(;wbMGTxOfQ=9+#m&HF>^10r;>s{Owg8Yavbb(7i5iKgkE-w|NUQ3~ z@+ui+b;8mlF$cy*rUviVPezd$XlbLV@KIEaPXzgp?W56nQ2EuSqCIQu$WDD`X#7d4 z&Bh;bCgTh{W_{`dM@%BcN*$h!u!;&T5d%gb|5I5)h1#d!(F=9fU2#N&IWB5);e_qJ zf{`|dOJO-D975cUYHVDBo_I@PHp33GJ1A`ox|VrM2a<#Yc}RSZiohYNHWJI!Owv0} zPe0AW)xiV?lz`L-`g3gwE*{7@SLg)Ab+ zbn2f8ABwYIdqOa-epgRq`{T$@BC+Gb=;?5)DPmt3kZ#0k2-8$^l@m%)(VNt85m=Uz zLKzLlS0Iw5Q&*sJ>_YMoG_1x6r$ZOKUwetUxAWd2jnQXBL$ zg!O0G);BKx)@iw>Ao zl9m~05FI=exo3Sz8vHWNSdC=u8{Pm+;5FhUYD#GnNT817{#+^I{+OzvH&)s=41|Lb zAwPcxO}8jCl%5%QB2py3KATv7&R*PYX8%Eu;;%mlA>EblRuH%drP-(-@)I0(pQ9M^ zD_WY@f5;J<_=&NpDnyp%J;va*^S1i3{ek&buy$rNbM*`_-rDUVcKp!!t)Qvu<>3AB zEOzd%;nm&(QQbehaN@1i@Zz}LZ?SU=DQ`0b6wP??9BjnD-v4RCdb~>6eZ#>zyz;$G z@#W%)v6?_u9Q@*F(E**W|Nz&i%7&&b?>o)!EeMfmV9Y26&=3XIv^Fp8FQ50JL6g zs0r<6-6Kr~uQJfr=)Nm6mg_ZnIfuIbV*W)!U>RfbOEH?51bXJk z*Qexh+vOMAAG539x{*{k-NyLOKztlP!wqK!TFSz#-a=+=<6a+c=6qgAILE8|@JP*` z2vP2#ijd}PhhLJ%awyYyA$hzA$}>@*GJSUeZV#YRESQ^w&op(ssz#f=O?1Q!2dXB6 z_b@i;eXN;2qx-UP($PCQ%NBc9)U8(C6OM100nt%6ph@HnFfne-T% z3cHEdT$N-2J?1<>IRKQ)-CRsnSmiZBch^S9L5&qOFkr$(Ac}iDO9rT3zDVsLkuiQT zHN021Zaf$QWxDDyn!KFCE-qK6W0*0U{G0@_Oy?oma8T)>^4)`XVy(7sSWDf18h_Fn zyJ?EaVSQ)!bwXj)Y=wr-;bcP!WJ*@Fu^#04klJ{T)j4*ybaJ^ib9zPcwm|3C;Hk!r zo?P)zGokQK6L2s&xux z>e5t*_^M%tOulZD_(A6^3%Fov7=|2O$zRmYM;b$~k5b-kVEVpqT+c30GaH?b*N=*D z_tULr-{?0CIwqq@d}u6cCaVl*9p&?%SH>KDQ=reOPP)X{I)}jrcP)FuGQHcylMF30 zPZu|iDz{$&c+9>i+&lFK*yf2uk6dsVe~vR@z!eilH?EkTA=6Hmy-B|vaZeY!lfB+fG~?*RD&#o1+)A`#=yKt9+|;-{^-x=9 zWZ&uQlL8ZMGuPmAN}y~dOP94?ICBS{(#uo8v9euwZ)7c@U;2GiiPtIoU{v9Z;|On( zHEUzDTR&j6y_tW6r|oOp8V@ID-dTM+L0)_1_-9#PD^p&demLJ>o(WTf@>b4?u(?{p z_s1+>CZv}ZewBMU{^KTAldxN zc{>>QJuN_yje$~nvN67mYT#xMYDn)cjY&pE7QGC07mZ~#SHPJnlj0=#v#d=H>gtx0 z_DKP-2w`$gd1A`xQT3+V0Z%e~PBIB6$+hcUm4>-@)yRwuo^yDmraKIy;-8@wbq89u!7l zrfBuz;A{P~y=Jq?(V7`j_c|F$;#i8a)skz5gE+Ay3^Maup+t5Ymuzth6g2?&LBoX# zJ_vc%Iu*O!pGGXxgT(2na!uUh!mqm26w6n;PId4OF>Dpu<`=pJ;=&$;If(!yLq!s@7XcIz6+ zSmYvRSGcY*uc;J5h|xJEXvED?pGDoFEjPqih*P2y&fuqi;k^8YkSuERnP7ix>5Bbq zIC@~RaWaqZP?SV+UVd_Lp1Vd$ zeB_I9u6d5Ce2r42q})Emn{Z-YR;4El*4Zd!_}&|JfQJcG2MMN6P3WUl7da>y2s%ry zyAEoYSBmhs$vwJoCd9y|1;@8;az;@JI+|j4HT_REO@3hGuh2v;dpDqI?rU!T1dF`v}hPa>XsnvD+j1wOc@uji6;|JU_`_0@j3_7es9VC#x;A<+bte)N@O$;=%xj-VXY?nC`sR-#<%R#r^wkB8L%ry8&Q*GO+ESAgDeWf9EPnFO7HV*v z^*TA`m=gt&wQI{<-Z4aVA&_coM3j|h<;2SsH2!D$R9&ICig95%(`U)}s}VGYoN;vF ztxtD(q|ET;gzDN2l7Hn7F}IogEc=UaT;)u!<|yx2C=I=yq`m)-w0OH-NUBc1u`yL0 zJxFnNzVJK4V1|+lP=|V{G0;G{Rd8a&&W^s4B>z^vyWNKVzi89**Z47^5&xH62ljO6FbL)`KG} zQ=?->7D?vufBOHKpP7?;nK zu*}n+hXQ$A+OB>hTXN)?<%|j0E^-|333h=;!9FT6-^ar{7)%0D4FBx8E-GJBV|loW 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 W$(is?{=SugKWkT;a|+q6hyDk6Mjd(p literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg new file mode 100644 index 000000000000..358c882b40d9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg @@ -0,0 +1,1602 @@ + + + + diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index a5cb9c347ae9..6aa76d5b210e 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -309,6 +309,17 @@ def test_polar_rmin(): ax.set_rmax(2.0) ax.set_rmin(0.5) +@image_comparison(baseline_images=['polar_theta_position']) +def test_polar_theta_position(): + r = np.arange(0, 3.0, 0.01) + theta = 2*np.pi*r + + fig = plt.figure() + ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True) + ax.plot(theta, r) + ax.set_theta_zero_location("NW") + ax.set_theta_direction('clockwise') + @image_comparison(baseline_images=['axvspan_epoch']) def test_axvspan_epoch(): from datetime import datetime From 6b7c7421265fe5789537b5c68c823cdd6158abce Mon Sep 17 00:00:00 2001 From: Michael Droettboom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Wed, 22 Jun 2011 15:26:37 -0400 Subject: [PATCH 007/214] Add CHANGELOG entry. --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 07eca61726bd..955b72b90fa9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2011-06-22 Add axes.labelweight parameter to set font weight to axis + labels - MGD. + 2011-06-16 Added *bottom* keyword parameter for the stem command. Also, implemented a legend handler for the stem plot. - JJL From 50a779983d6ff66ca65687f02ae62837a9c78151 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Wed, 22 Jun 2011 16:47:10 -0500 Subject: [PATCH 008/214] First step in having the axes3d methods match with the axes objects and to have an equivalent z-function as well. --- lib/mpl_toolkits/mplot3d/axes3d.py | 54 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 72f70be009cf..2055091f24be 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -252,8 +252,8 @@ def _determine_lims(self, xmin=None, xmax=None, *args, **kwargs): if xmax is None and cbook.iterable(xmin): xmin, xmax = xmin if xmin == xmax: - xmin -= 0.5 - xmax += 0.5 + xmin -= 0.05 + xmax += 0.05 return (xmin, xmax) def set_xlim3d(self, *args, **kwargs): @@ -337,11 +337,11 @@ def get_zticklines(self) : def clabel(self, *args, **kwargs): return None - def pany(self, numsteps): - print 'numsteps', numsteps + #def pany(self, numsteps): + # print 'numsteps', numsteps - def panpy(self, numsteps): - print 'numsteps', numsteps + #def panpy(self, numsteps): + # print 'numsteps', numsteps def view_init(self, elev=None, azim=None): """ @@ -446,6 +446,9 @@ def mouse_init(self, rotate_btn=1, zoom_btn=3): self._rotate_btn = np.atleast_1d(rotate_btn) self._zoom_btn = np.atleast_1d(zoom_btn) + def can_zoom(self) : + return False + def cla(self): """Clear axes and disable mouse button callbacks. """ @@ -470,6 +473,7 @@ def _button_press(self, event): def _button_release(self, event): self.button_pressed = None + ''' def format_xdata(self, x): """ Return x string formatted. This function will use the attribute @@ -493,18 +497,19 @@ def format_ydata(self, y): except TypeError: fmt = self.w_yaxis.get_major_formatter() return sensible_format_data(fmt, y) + ''' def format_zdata(self, z): """ - Return z string formatted. This function will use the attribute - self.fmt_zdata if it is callable, else will fall back on the yaxis - major formatter + Return *z* string formatted. This function will use the + :attr:`fmt_zdata` attribute if it is callable, else will fall + back on the zaxis major formatter """ - try: - return self.fmt_zdata(z) + try: return self.fmt_zdata(z) except (AttributeError, TypeError): - fmt = self.w_zaxis.get_major_formatter() - return sensible_format_data(fmt, z) + func = self.zaxis.get_major_formatter().format_data_short + val = func(z) + return val def format_coord(self, xd, yd): """ @@ -543,7 +548,7 @@ def format_coord(self, xd, yd): xs = self.format_xdata(x) ys = self.format_ydata(y) - zs = self.format_ydata(z) + zs = self.format_zdata(z) return 'x=%s, y=%s, z=%s' % (xs, ys, zs) def _on_move(self, event): @@ -603,6 +608,7 @@ def _on_move(self, event): self.get_proj() self.figure.canvas.draw() + """ def set_xlabel(self, xlabel, fontdict=None, **kwargs): '''Set xlabel.''' @@ -622,16 +628,18 @@ def set_ylabel(self, ylabel, fontdict=None, **kwargs): label.update(fontdict) label.update(kwargs) return label + """ + def set_zlabel(self, zlabel, fontdict=None, labelpad=None, **kwargs): + '''Set zlabel. See doc for :meth:`set_xlabel` for description.''' + if labelpad is not None : self.zaxis.labelpad = labelpad + return self.zaxis.set_label_text(zlabel, fontdict, **kwargs) - def set_zlabel(self, zlabel, fontdict=None, **kwargs): - '''Set zlabel.''' - - label = self.w_zaxis.get_label() - label.set_text(zlabel) - if fontdict is not None: - label.update(fontdict) - label.update(kwargs) - return label + def get_zlabel(self) : + """ + Get the z-label text string. + """ + label = self.zaxis.get_label() + return label.get_text() def grid(self, on=True, **kwargs): ''' From 9b87fbc7f67f98d6d365015bf1fa6c2e1517f99f Mon Sep 17 00:00:00 2001 From: Hans Meine Date: Thu, 23 Jun 2011 13:59:33 +0200 Subject: [PATCH 009/214] fix axes parameter editing when titles contain percent characters I got an exception when pressing the "edit curves line and axes parameter" button on a plot with '%' in a subplot title: Traceback (most recent call last): File "/usr/lib/pymodules/python2.6/matplotlib/backends/backend_qt4.py", line 456, in edit_parameters titles.append(text % repr(axes)) ValueError: unsupported format character ')' (0x29) at index 38 I had used sth. like: pylab.title("differences (in %)") --- lib/matplotlib/backends/backend_qt4.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 884cbe22ebcd..76ba765508aa 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -447,15 +447,17 @@ def edit_parameters(self): title = axes.get_title() ylabel = axes.get_ylabel() if title: - text = title + fmt = "%(title)s" if ylabel: - text += ": "+ylabel - text += " (%s)" + fmt += ": %(ylabel)s" + fmt += " (%(axes_repr)s)" elif ylabel: - text = "%%s (%s)" % ylabel + fmt = "%(axes_repr)s (%(ylabel)s)" % ylabel else: - text = "%s" - titles.append(text % repr(axes)) + fmt = "%(axes_repr)s" + titles.append(fmt % dict(title = title, + ylabel = ylabel, + axes_repr = repr(axes))) item, ok = QtGui.QInputDialog.getItem(self, 'Customize', 'Select axes:', titles, 0, False) From f60df9f8afb48717cceb389ff40164795a14629f Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 23 Jun 2011 11:01:16 -0400 Subject: [PATCH 010/214] Fix bug in TkAgg backend opening/closing multiple figure windows when interactive: True. --- lib/matplotlib/backends/backend_tkagg.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index 9c07cbc954af..7aae9d9016a0 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -176,6 +176,7 @@ class FigureCanvasTkAgg(FigureCanvasAgg): def __init__(self, figure, master=None, resize_callback=None): FigureCanvasAgg.__init__(self, figure) self._idle = True + self._idle_callback = None t1,t2,w,h = self.figure.bbox.bounds w, h = int(w), int(h) self._tkcanvas = Tk.Canvas( @@ -263,7 +264,8 @@ def idle_draw(*args): self.draw() self._idle = True - if d: self._tkcanvas.after_idle(idle_draw) + if d: + self._idle_callback = self._tkcanvas.after_idle(idle_draw) def get_tk_widget(self): """returns the Tk widget used to implement FigureCanvasTkAgg. @@ -454,13 +456,15 @@ def destroy(*args): def destroy(self, *args): - if Gcf.get_num_fig_managers()==0 and not matplotlib.is_interactive(): - if self.window is not None: - self.window.quit() if self.window is not None: #self.toolbar.destroy() + if self.canvas._idle_callback: + self.canvas._tkcanvas.after_cancel(self.canvas._idle_callback) self.window.destroy() - self.window = None + if Gcf.get_num_fig_managers()==0: + if self.window is not None: + self.window.quit() + self.window = None def set_window_title(self, title): self.window.wm_title(title) From aea66e07845bd749a63fc9815fb78e65e51afb7c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 23 Jun 2011 11:13:40 -0400 Subject: [PATCH 011/214] Yet more improvments to finding Tcl/Tk. Recent versions of Tcl/Tk put "real" bash code in tclConfig.sh and tkConfig.sh so the hackish "treat this as an ini file" approach no longer works. The new way is to actually source the file with bash and "eval echo" environment variables to get the results back. This should work fine on Unices -- it doesn't have to work on Windows since we use a more hard-coded config there. --- setupext.py | 77 +++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/setupext.py b/setupext.py index 5af214cfe942..b949e22291b0 100644 --- a/setupext.py +++ b/setupext.py @@ -914,9 +914,11 @@ def query_tcltk(): def parse_tcl_config(tcl_lib_dir, tk_lib_dir): import Tkinter tcl_poss = [tcl_lib_dir, + os.path.normpath(os.path.join(tcl_lib_dir, '..')), "/usr/lib/tcl"+str(Tkinter.TclVersion), "/usr/lib"] tk_poss = [tk_lib_dir, + os.path.normpath(os.path.join(tk_lib_dir, '..')), "/usr/lib/tk"+str(Tkinter.TkVersion), "/usr/lib"] for ptcl, ptk in zip(tcl_poss, tk_poss): @@ -927,52 +929,29 @@ def parse_tcl_config(tcl_lib_dir, tk_lib_dir): if not (os.path.exists(tcl_config) and os.path.exists(tk_config)): return None - # These files are shell scripts that set a bunch of - # environment variables. To actually get at the - # values, we use ConfigParser, which supports almost - # the same format, but requires at least one section. - # So, we push a "[default]" section to a copy of the - # file in a StringIO object. - try: - tcl_vars_str = cStringIO.StringIO( - "[default]\n" + open(tcl_config, "r").read()) - tk_vars_str = cStringIO.StringIO( - "[default]\n" + open(tk_config, "r").read()) - except IOError: - # if we can't read the file, that's ok, we'll try - # to guess instead - return None - - tcl_vars_str.seek(0) - tcl_vars = ConfigParser.RawConfigParser() - tk_vars_str.seek(0) - tk_vars = ConfigParser.RawConfigParser() - try: - tcl_vars.readfp(tcl_vars_str) - tk_vars.readfp(tk_vars_str) - except ConfigParser.ParsingError: - # if we can't read the file, that's ok, we'll try - # to guess instead - return None - - try: - tcl_lib = tcl_vars.get("default", "TCL_LIB_SPEC")[1:-1].split()[0][2:] - tcl_inc = tcl_vars.get("default", "TCL_INCLUDE_SPEC")[3:-1] - - tk_lib = tk_vars.get("default", "TK_LIB_SPEC")[1:-1].split()[0][2:] - if tk_vars.has_option("default", "TK_INCLUDE_SPEC"): - # On Ubuntu 8.04 - tk_inc = tk_vars.get("default", "TK_INCLUDE_SPEC")[3:-1] - else: - # On RHEL4 - tk_inc = tcl_inc - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): - return None + def get_var(file, varname): + p = subprocess.Popen( + 'source %s ; eval echo ${%s}' % (file, varname), + shell=True, stdout=subprocess.PIPE) + result = p.communicate()[0] + return result + + tcl_lib_dir = get_var(tcl_config, 'TCL_LIB_SPEC').split()[0][2:] + tcl_inc_dir = get_var(tcl_config, 'TCL_INCLUDE_SPEC')[2:] + tcl_lib = get_var(tcl_config, 'TCL_LIB_FLAG')[2:].strip() + + tk_lib_dir = get_var(tk_config, 'TK_LIB_SPEC').split()[0][2:] + tk_inc_dir = get_var(tk_config, 'TK_INCLUDE_SPEC').strip() + if tk_inc_dir == '': + tk_inc_dir = tcl_inc_dir + else: + tk_inc_dir = tk_inc_dir[2:] + tk_lib = get_var(tk_config, 'TK_LIB_FLAG')[2:].strip() - if not os.path.exists(os.path.join(tk_inc, 'tk.h')): + if not os.path.exists(os.path.join(tk_inc_dir, 'tk.h')): return None - return tcl_lib, tcl_inc, tk_lib, tk_inc + return tcl_lib_dir, tcl_inc_dir, tcl_lib, tk_lib_dir, tk_inc_dir, tk_lib def guess_tcl_config(tcl_lib_dir, tk_lib_dir, tk_ver): if not (os.path.exists(tcl_lib_dir) and os.path.exists(tk_lib_dir)): @@ -1007,14 +986,14 @@ def guess_tcl_config(tcl_lib_dir, tk_lib_dir, tk_ver): if not os.path.exists(os.path.join(tk_inc, 'tk.h')): return None - return tcl_lib, tcl_inc, tk_lib, tk_inc + return tcl_lib, tcl_inc, 'tcl' + tk_ver, tk_lib, tk_inc, 'tk' + tk_ver def hardcoded_tcl_config(): tcl_inc = "/usr/local/include" tk_inc = "/usr/local/include" tcl_lib = "/usr/local/lib" tk_lib = "/usr/local/lib" - return tcl_lib, tcl_inc, tk_lib, tk_inc + return tcl_lib, tcl_inc, 'tcl', tk_lib, tk_inc, 'tk' def add_tk_flags(module): 'Add the module flags to build extensions which use tk' @@ -1115,10 +1094,10 @@ def add_tk_flags(module): result = hardcoded_tcl_config() # Add final versions of directories and libraries to module lists - tcl_lib, tcl_inc, tk_lib, tk_inc = result - module.include_dirs.extend([tcl_inc, tk_inc]) - module.library_dirs.extend([tcl_lib, tk_lib]) - module.libraries.extend(['tk' + tk_ver, 'tcl' + tk_ver]) + tcl_lib_dir, tcl_inc_dir, tcl_lib, tk_lib_dir, tk_inc_dir, tk_lib = result + module.include_dirs.extend([tcl_inc_dir, tk_inc_dir]) + module.library_dirs.extend([tcl_lib_dir, tk_lib_dir]) + module.libraries.extend([tcl_lib, tk_lib]) return message From c082e2186f5fae3f5e29bb80998d877198b6fba9 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Thu, 23 Jun 2011 15:16:18 -0500 Subject: [PATCH 012/214] BREAKING COMMIT! Significant addition of functions to bring Axes3D to (ear) feature parity with Axes. This commit is just a step in a longer process. Functions were more-or-less blindly added to Axes3D. While the examples will "run", many of them do not function properly any more. --- lib/mpl_toolkits/mplot3d/axes3d.py | 655 ++++++++++++++++++++++++----- 1 file changed, 557 insertions(+), 98 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 2055091f24be..3dbc06e7937c 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -3,6 +3,7 @@ # Created: 23 Sep 2005 # Parts fixed by Reinier Heeres # Minor additions by Ben Axelrod +# Significant updates and revisions by Ben Root """ Module containing Axes3D, an object which can plot 3D objects on a @@ -10,10 +11,14 @@ """ import warnings +import matplotlib.axes as maxes from matplotlib.axes import Axes, rcParams from matplotlib import cbook +import matplotlib.transforms as mtransforms from matplotlib.transforms import Bbox -from matplotlib import collections +import matplotlib.collections as mcoll +from matplotlib import docstring +import matplotlib.scale as mscale import numpy as np from matplotlib.colors import Normalize, colorConverter, LightSource @@ -21,14 +26,6 @@ import proj3d import axis3d -def sensible_format_data(self, value): - """Used to generate more comprehensible numbers in status bar""" - if abs(value) > 1e4 or abs(value)<1e-3: - s = '%1.4e' % value - return self._formatSciNotation(s) - else: - return '%4.3f' % value - def unit_bbox(): box = Bbox(np.array([[0, 0], [1, 1]])) return box @@ -53,15 +50,19 @@ def __init__(self, fig, rect=None, *args, **kwargs): ================ ========================================= *azim* Azimuthal viewing angle (default -60) *elev* Elevation viewing angle (default 30) + *zscale* [%(scale)s] ================ ========================================= - ''' + ''' % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} if rect is None: rect = [0.0, 0.0, 1.0, 1.0] self._cids = [] + # TODO: Support z-axis sharing + self.initial_azim = kwargs.pop('azim', -60) self.initial_elev = kwargs.pop('elev', 30) + zscale = kwargs.pop('zscale', None) self.xy_viewLim = unit_bbox() self.zz_viewLim = unit_bbox() @@ -77,9 +78,20 @@ def __init__(self, fig, rect=None, *args, **kwargs): *args, **kwargs) # Disable drawing of axes by base class Axes.set_axis_off(self) - self._axis3don = True + # Enable drawing of axes by Axes3D class + self.set_axis_on() self.M = None + # func used to format z -- fall back on major formatters + self.fmt_zdata = None + + if zscale is not None : + self.set_zscale(zscale) + + if self.zaxis is not None : + self._zcid = self.zaxis.callbacks.connect('units finalize', + self.relim) + self._ready = 1 self.mouse_init() self.set_top_view() @@ -205,6 +217,139 @@ def get_axis_position(self): def update_datalim(self, xys, **kwargs): pass + def get_autoscale_on(self) : + """ + Get whether autoscaling is applied for all axes on plot commands + """ + return Axes.get_autoscale_on(self) and self.get_autoscalez_on() + + def get_autoscalez_on(self) : + """ + Get whether autoscaling for the z-axis is applied on plot commands + """ + return self._autoscaleZon + + def set_autoscale_on(self, b) : + """ + Set whether autoscaling is applied on plot commands + + accepts: [ *True* | *False* ] + """ + Axes.set_autoscale_on(self, b) + self.set_autoscalez_on(self, b) + + def set_autoscalez_on(self, b) : + """ + Set whether autoscaling for the z-axis is applied on plot commands + + accepts: [ *True* | *False* ] + """ + self._autoscalez_on = b + + def set_zmargin(self, m) : + """ + Set padding of Z data limits prior to autoscaling. + + *m* times the data interval will be added to each + end of that interval before it is used in autoscaling. + + accepts: float in range 0 to 1 + """ + if m < 0 or m > 1 : + raise ValueError("margin must be in range 0 to 1") + self._zmargin = m + + def margins(self, *args, **kw) : + """ + Convenience method to set or retrieve autoscaling margins. + + signatures:: + margins() + + returns xmargin, ymargin, zmargin + + :: + + margins(margin) + + margins(xmargin, ymargin, zmargin) + + margins(x=xmargin, y=ymargin, z=zmargin) + + margins(..., tight=False) + + All three forms above set the xmargin, ymargin and zmargin + parameters. All keyword parameters are optional. A single argument + specifies xmargin, ymargin and zmargin. The *tight* parameter + is passed to :meth:`autoscale_view`, which is executed after + a margin is changed; the default here is *True*, on the + assumption that when margins are specified, no additional + padding to match tick marks is usually desired. Setting + *tight* to *None* will preserve the previous setting. + + Specifying any margin changes only the autoscaling; for example, + if *xmargin* is not None, then *xmargin* times the X data + interval will be added to each end of that interval before + it is used in autoscaling. + """ + if not args and not kw: + return self._xmargin, self._ymargin, self._zmargin + + tight = kw.pop('tight', True) + mx = kw.pop('x', None) + my = kw.pop('y', None) + mz = kw.pop('z', None) + if len(args) == 1: + mx = my = mz = args[0] + elif len(args) == 2: + # Maybe put out a warning because mz is not set? + mx, my = args + elif len(args) == 3: + mx, my, mz = args + else: + raise ValueError("more than three arguments were supplied") + if mx is not None: + self.set_xmargin(mx) + if my is not None: + self.set_ymargin(my) + if mz is not None: + self.set_zmargin(mz) + + scalex = (mx is not None) + scaley = (my is not None) + scalez = (mz is not None) + + self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley, + scalez=scalez) + + def autoscale(self, enable=True, axis='both', tight=None) : + """ + Convenience method for simple axis view autoscaling. + See :meth:`matplotlib.axes.Axes.autoscale` for full explanation. + Note that this function behaves the same, but for all + three axes. Therfore, 'z' can be passed for *axis*, + and 'both' applies to all three axes. + """ + if enable is None: + scalex = True + scaley = True + scalez = True + else: + scalex = False + scaley = False + scalez = False + if axis in ['x', 'both']: + self._autoscaleXon = bool(enable) + scalex = self._autoscaleXon + if axis in ['y', 'both']: + self._autoscaleYon = bool(enable) + scaley = self._autoscaleYon + if axis in ['z', 'both']: + self._autoscaleZon = bool(enable) + scalez = self._autoscaleZon + self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley, + scalez=scalez) + def auto_scale_xyz(self, X, Y, Z=None, had_data=None): x, y, z = map(np.asarray, (X, Y, Z)) try: @@ -224,22 +369,60 @@ def auto_scale_xyz(self, X, Y, Z=None, had_data=None): # Let autoscale_view figure out how to use this data. self.autoscale_view() - def autoscale_view(self, scalex=True, scaley=True, scalez=True, **kw): + def autoscale_view(self, tight=None, scalex=True, scaley=True, + scalez=True) : + """ + Autoscale the view limits using the data limits. + See :meth:`matplotlib.axes.Axes.autoscale_view` for documentation. + Note that this function applies to the 3d axes, and as such + adds the *scalez* to the function arguments. + """ # This method looks at the rectangular volume (see above) # of data and decides how to scale the view portal to fit it. + if tight is None: + # if image data only just use the datalim + _tight = self._tight or (len(self.images)>0 and + len(self.lines)==0 and + len(self.patches)==0) + else: + _tight = self._tight = bool(tight) + self.set_top_view() if not self._ready: return - if not self.get_autoscale_on(): - return - if scalex: - self.set_xlim3d(self.xy_dataLim.intervalx) - if scaley: - self.set_ylim3d(self.xy_dataLim.intervaly) - if scalez: - self.set_zlim3d(self.zz_dataLim.intervalx) + Axes.autoscale_view(self, tight=_tight, scalex=scalex, scaley=scaley) + + if scalez and self._autoscaleZon: + # TODO: mplot3d does not support the sharing of Z axis. + #zshared = self._shared_z_axes.get_siblings(self) + #dl = [ax.dataLim for ax in zshared] + #bb = mtransforms.BboxBase.union(dl) + z0, z1 = self.zz_dataLim.intervalx + zlocator = self.zaxis.get_major_locator() + try: + z0, z1 = zlocator.nonsingular(z0, z1) + except AttributeError: + z0, z1 = mtransforms.nonsingular(z0, z1, increasing=False, + expander=0.05) + if self._zmargin > 0: + delta = (z1 - z0) * self._zmargin + z0 -= delta + z1 += delta + if not _tight: + z0, z1 = zlocator.view_limits(z0, z1) + self.set_zbound(z0, z1) + + # Previous version's code + #if not self.get_autoscale_on(): + # return + #if scalex: + # self.set_xlim3d(self.xy_dataLim.intervalx) + #if scaley: + # self.set_ylim3d(self.xy_dataLim.intervaly) + #if scalez: + # self.set_zlim3d(self.zz_dataLim.intervalx) def get_w_lims(self): '''Get 3d world limits.''' @@ -257,74 +440,171 @@ def _determine_lims(self, xmin=None, xmax=None, *args, **kwargs): return (xmin, xmax) def set_xlim3d(self, *args, **kwargs): - '''Set 3D x limits.''' + ''' + Set 3D x limits. + + See :meth:`matplotlib.axes.Axes.set_xlim` for full documentation. + ''' + # TODO: Add compatibility for 'left' and 'right' + # TODO: support 'emit' and 'auto' lims = self._determine_lims(*args, **kwargs) self.xy_viewLim.intervalx = lims return lims set_xlim = set_xlim3d def set_ylim3d(self, *args, **kwargs): - '''Set 3D y limits.''' + ''' + Set 3D y limits. + + See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation. + ''' + # TODO: Add compatibility for 'top' and 'bottom' + # TODO: support 'emit' and 'auto' lims = self._determine_lims(*args, **kwargs) self.xy_viewLim.intervaly = lims return lims set_ylim = set_ylim3d def set_zlim3d(self, *args, **kwargs): - '''Set 3D z limits.''' + ''' + Set 3D z limits. + + See :meth:`matplotlib.axes.Axes.set_ylim` for full documentation. + ''' + # TODO: Add compatibility for 'top' and 'bottom' + # TODO: support 'emit' and 'auto' lims = self._determine_lims(*args, **kwargs) self.zz_viewLim.intervalx = lims return lims set_zlim = set_zlim3d def get_xlim3d(self): - '''Get 3D x limits.''' return self.xy_viewLim.intervalx + get_xlim3d.__doc__ = maxes.Axes.get_xlim.__doc__ + get_xlim = get_xlim3d def get_ylim3d(self): - '''Get 3D y limits.''' return self.xy_viewLim.intervaly + get_ylim3d.__doc__ = maxes.Axes.get_ylim.__doc__ + get_ylim = get_ylim3d def get_zlim3d(self): '''Get 3D z limits.''' return self.zz_viewLim.intervalx get_zlim = get_zlim3d + def get_zscale(self) : + """ + Return the zaxis scale string %s + """ % (", ".join(mscale.get_scale_names())) + return self.zaxis.get_scale() + + # We need to slightly redefine these to pass scalez=False + # to their calls of autoscale_view. + def set_xscale(self, value, **kwargs) : + self.xaxis.set_scale(value, **kwargs) + self.autoscale_view(scaley=False, scalez=False) + self._update_transScale() + set_xscale.__doc__ = maxes.Axes.set_xscale.__doc__ + + def set_yscale(self, value, **kwargs) : + self.yaxis.set_scale(value, **kwargs) + self.autoscale_view(scalex=False, scalez=False) + self._update_transScale() + set_yscale.__doc__ = maxes.Axes.set_yscale.__doc__ + + @docstring.dedent_interpd + def set_zscale(self, value, **kwargs) : + """ + call signature:: + + set_zscale(value) + + Set the scaling of the z-axis: %(scale)s + + ACCEPTS: [%(scale)s] + + Different kwargs are accepted, depending on the scale: + %(scale_docs)s + + .. note :: + Currently, Axes3D objects only supports linear scales. + Other scales may or may not work, and support for these + is improving with each release. + """ + self.zaxis.set_scale(value, **kwargs) + self.autoscale_view(scalex=False, scaley=False) + self._update_transScale() + def set_zticks(self, *args, **kwargs): """ Set z-axis tick locations. - See set_xticks for more details. + See :meth:`matplotlib.axes.Axes.set_yticks` for more details. Note that minor ticks are not supported at this time. """ - return self.w_zaxis.set_ticks(*args, **kwargs) + return self.zaxis.set_ticks(*args, **kwargs) def get_zticks(self, *args, **kwargs): """ Get the z-axis tick objects. - See get_xticks for more details. + See :meth:`matplotlib.axes.Axes.get_yticks` for more details. Note that minor ticks are not supported at this time. """ - return self.w_zaxis.get_ticks(*args, **kwargs) + return self.zaxis.get_ticks(*args, **kwargs) + + def get_zmajorticklabels(self) : + """ + Get the ztick labels as a list of Text instances + """ + return cbook.silent_list('Text zticklabel', + self.zaxis.get_majorticklabels()) + + def get_zminorticklabels(self) : + """ + Get the ztick labels as a list of Text instances + + .. note:: + Currently, Axes3D objects do not support minor ticks + """ + return cbook.silent_list('Text zticklabel', + self.zaxis.get_minorticklabels()) def set_zticklabels(self, *args, **kwargs) : """ Set z-axis tick labels. - See set_xticklabels for more details. + See :meth:`matplotlib.axes.Axes.set_yticklabels` for more details. - Note that minor ticks are not supported at this time. + .. note:: + Currently, minor ticks are not supported by Axes3D objects. """ - return self.w_zaxis.set_ticklabels(*args, **kwargs) + return self.zaxis.set_ticklabels(*args, **kwargs) - def get_zticklabels(self, *args, **kwargs) : + def get_zticklabels(self, minor=False) : """ Get ztick labels as a list of Text instances. - Set get_xticklabels for more details. + See :meth:`matplotlib.axes.Axes.get_yticklabels` for more details. - Note that minor ticks are not supported at this time. + .. note:: + Minor ticks are not supported at this time in Axes3D objects. """ - return self.w_zaxis.get_ticklabels(*args, **kwargs) + return cbook.silent_list('Text zticklabel', + self.zaxis.get_ticklabels(minor=minor)) + + def zaxis_date(self, tz=None) : + """ + Sets up z-axis ticks and labels that treat the z data as dates. + + *tz* is a timezone string or :class:`tzinfo` instance. + Defaults to rc value. + + .. note:: + This function is merely provided for completeness. + Axes3D objects do not officially support dates for ticks, + and so this may or may not work as expected. + """ + self.zaxis.axis_date(tz) def get_zticklines(self) : """ @@ -332,17 +612,15 @@ def get_zticklines(self) : Note that this function is provided merely for completeness. These lines are re-calculated as the display changes. """ - return self.w_zaxis.get_ticklines() + return self.zaxis.get_ticklines() def clabel(self, *args, **kwargs): + """ + This function is currently not implemented for 3d axes. + Returns *None*. + """ return None - #def pany(self, numsteps): - # print 'numsteps', numsteps - - #def panpy(self, numsteps): - # print 'numsteps', numsteps - def view_init(self, elev=None, azim=None): """ Set the elevation and azimuth of the axes. @@ -369,8 +647,8 @@ def view_init(self, elev=None, azim=None): self.azim = azim def get_proj(self): - """Create the projection matrix from the current viewing - position. + """ + Create the projection matrix from the current viewing position. elev stores the elevation angle in the z plane azim stores the azimuth angle in the x,y plane @@ -453,7 +731,25 @@ def cla(self): """Clear axes and disable mouse button callbacks. """ self.disable_mouse_rotation() + self.zaxis.cla() + + # TODO: Support sharez + self._sharez = None + + if self._sharez is not None: + self.zaxis.major = self._sharez.zaxis.major + self.zaxis.minor = self._sharez.zaxis.minor + z0, z1 = self._sharez.get_zlim() + self.set_zlim(z0, z1, emit=False, auto=None) + self.zaxis.set_scale(self._sharez.zaxis.get_scale()) + else: + self.zaxis.set_scale('linear') + + self._autoscaleZon = True + self._zmargin = 0 + Axes.cla(self) + self.grid(rcParams['axes3d.grid']) def disable_mouse_rotation(self): @@ -473,32 +769,6 @@ def _button_press(self, event): def _button_release(self, event): self.button_pressed = None - ''' - def format_xdata(self, x): - """ - Return x string formatted. This function will use the attribute - self.fmt_xdata if it is callable, else will fall back on the xaxis - major formatter - """ - try: - return self.fmt_xdata(x) - except TypeError: - fmt = self.w_xaxis.get_major_formatter() - return sensible_format_data(fmt, x) - - def format_ydata(self, y): - """ - Return y string formatted. This function will use the attribute - self.fmt_ydata if it is callable, else will fall back on the yaxis - major formatter - """ - try: - return self.fmt_ydata(y) - except TypeError: - fmt = self.w_yaxis.get_major_formatter() - return sensible_format_data(fmt, y) - ''' - def format_zdata(self, z): """ Return *z* string formatted. This function will use the @@ -608,27 +878,6 @@ def _on_move(self, event): self.get_proj() self.figure.canvas.draw() - """ - def set_xlabel(self, xlabel, fontdict=None, **kwargs): - '''Set xlabel.''' - - label = self.w_xaxis.get_label() - label.set_text(xlabel) - if fontdict is not None: - label.update(fontdict) - label.update(kwargs) - return label - - def set_ylabel(self, ylabel, fontdict=None, **kwargs): - '''Set ylabel.''' - - label = self.w_yaxis.get_label() - label.set_text(ylabel) - if fontdict is not None: - label.update(fontdict) - label.update(kwargs) - return label - """ def set_zlabel(self, zlabel, fontdict=None, labelpad=None, **kwargs): '''Set zlabel. See doc for :meth:`set_xlabel` for description.''' if labelpad is not None : self.zaxis.labelpad = labelpad @@ -641,11 +890,219 @@ def get_zlabel(self) : label = self.zaxis.get_label() return label.get_text() - def grid(self, on=True, **kwargs): + #### Axes rectangle characteristics + + def get_frame_on(self): + """ + Get whether the 3d axes panels are drawn + """ + return self._frameon + + def set_frame_on(self, b): + """ + Set whether the 3d axes panels are drawn + + ACCEPTS: [ *True* | *False* ] + """ + self._frameon = b + + def get_axisbelow(self): + """ + Get whether axis below is true or not. + + For axes3d objects, this will always be *True* + """ + return True + + def set_axisbelow(self, b): + """ + Set whether the axis ticks and gridlines are above or below + most artists + + For axes3d objects, this will ignore any settings and just use *True* + + ACCEPTS: [ *True* | *False* ] + """ + self._axisbelow = True + + def grid(self, b=True, **kwargs): ''' Set / unset 3D grid. + + Currently, this function does not behave the same as + :meth:`matplotlib.axes.Axes.grid`, but it is intended to + eventually support that behavior. ''' - self._draw_grid = on + # TODO: Operate on each axes separately + if len(kwargs) : + b = True + self._draw_grid = maxes._string_to_bool(b) + + def ticklabel_format(self, **kwargs) : + """ + Convenience method for manipulating the ScalarFormatter + used by default for linear axes in Axed3D objects. + + See :meth:`matplotlib.axes.Axes.ticklabel_format` for full + documentation. Note that this version applies to all three + axes of the Axes3D object. Therefore, the *axis* argument + will also accept a value of 'z' and the value of 'both' will + apply to all three axes. + """ + style = kwargs.pop('style', '').lower() + scilimits = kwargs.pop('scilimits', None) + useOffset = kwargs.pop('useOffset', None) + axis = kwargs.pop('axis', 'both').lower() + if scilimits is not None: + try: + m, n = scilimits + m+n+1 # check that both are numbers + except (ValueError, TypeError): + raise ValueError("scilimits must be a sequence of 2 integers") + if style[:3] == 'sci': + sb = True + elif style in ['plain', 'comma']: + sb = False + if style == 'plain': + cb = False + else: + cb = True + raise NotImplementedError, "comma style remains to be added" + elif style == '': + sb = None + else: + raise ValueError, "%s is not a valid style value" + try: + if sb is not None: + if axis in ['both', 'z']: + self.xaxis.major.formatter.set_scientific(sb) + if axis in ['both', 'y']: + self.yaxis.major.formatter.set_scientific(sb) + if axis in ['both', 'z'] : + self.zaxis.major.formatter.set_scientific(sb) + if scilimits is not None: + if axis in ['both', 'x']: + self.xaxis.major.formatter.set_powerlimits(scilimits) + if axis in ['both', 'y']: + self.yaxis.major.formatter.set_powerlimits(scilimits) + if axis in ['both', 'z']: + self.zaxis.major.formatter.set_powerlimits(scilimits) + if useOffset is not None: + if axis in ['both', 'x']: + self.xaxis.major.formatter.set_useOffset(useOffset) + if axis in ['both', 'y']: + self.yaxis.major.formatter.set_useOffset(useOffset) + if axis in ['both', 'z']: + self.zaxis.major.formatter.set_useOffset(useOffset) + except AttributeError: + raise AttributeError( + "This method only works with the ScalarFormatter.") + + def locator_params(self, axis='both', tight=None, **kwargs) : + """ + Convenience method for controlling tick locators. + + See :meth:`matplotlib.axes.Axes.locator_params` for full + documentation Note that this is for Axes3D objects, + therefore, setting *axis* to 'both' will result in the + parameters being set for all three axes. Also, *axis* + can also take a value of 'z' to apply parameters to the + z axis. + """ + _x = axis in ['x', 'both'] + _y = axis in ['y', 'both'] + _z = axis in ['z', 'both'] + if _x: + self.xaxis.get_major_locator().set_params(**kwargs) + if _y: + self.yaxis.get_major_locator().set_params(**kwargs) + if _z: + self.zaxis.get_major_locator().set_params(**kwargs) + self.autoscale_view(tight=tight, scalex=_x, scaley=_y, scalez=_z) + + def tick_params(self, axis='both', **kwargs) : + """ + Convenience method for changing the appearance of ticks and + tick labels. + + See :meth:`matplotlib.axes.Axes.tick_params` for more complete + documentation. + + The only difference is that setting *axis* to 'both' will + mean that the settings are applied to all three axes. Also, + the *axis* parameter also accepts a value of 'z', which + would mean to apply to only the z-axis. + + Also, because of how Axes3D objects are drawn very differently + from regular 2D axes, some of these settings may have + ambiguous meaning. For simplicity, the 'z' axis will + accept settings as if it was like the 'y' axis. + + .. note:: + While this function is currently implemented, the core part + of the Axes3D object may ignore some of these settings. + Future releases will fix this. + """ + Axes.tick_params(self, axis, **kwargs) + if axis in ['z', 'both'] : + zkw = dict(kwargs) + zkw.pop('top', None) + zkw.pop('bottom', None) + zkw.pop('labeltop', None) + zkw.pop('labelbottom', None) + self.zaxis.set_tick_params(**zkw) + + ### data limits, ticks, tick labels, and formatting + + def invert_zaxis(self): + "Invert the z-axis." + bottom, top = self.get_zlim() + self.set_zlim(top, bottom) + + def zaxis_inverted(self): + 'Returns True if the z-axis is inverted.' + bottom, top = self.get_zlim() + return top < bottom + + def get_zbound(self): + """ + Returns the z-axis numerical bounds where:: + + lowerBound < upperBound + + """ + bottom, top = self.get_zlim() + if bottom < top: + return bottom, top + else: + return top, bottom + + def set_zbound(self, lower=None, upper=None): + """ + Set the lower and upper numerical bounds of the z-axis. + This method will honor axes inversion regardless of parameter order. + It will not change the :attr:`_autoscaleZon` attribute. + """ + if upper is None and iterable(lower): + lower,upper = lower + + old_lower,old_upper = self.get_zbound() + + if lower is None: lower = old_lower + if upper is None: upper = old_upper + + if self.zaxis_inverted(): + if lower < upper: + self.set_zlim(upper, lower, auto=None) + else: + self.set_zlim(lower, upper, auto=None) + else : + if lower < upper: + self.set_zlim(lower, upper, auto=None) + else : + self.set_zlim(upper, lower, auto=None) + + def text(self, x, y, z, s, zdir=None, **kwargs): ''' @@ -1141,14 +1598,16 @@ def add_collection3d(self, col, zs=0, zdir='z'): - LineColleciton - PatchCollection ''' - - if type(col) is collections.PolyCollection: + # FIXME: use issubclass() (although, then a 3D collection + # object would also pass.) Maybe have a collection3d + # abstract class to test for and exclude? + if type(col) is mcoll.PolyCollection: art3d.poly_collection_2d_to_3d(col, zs=zs, zdir=zdir) col.set_sort_zpos(min(zs)) - elif type(col) is collections.LineCollection: + elif type(col) is mcoll.LineCollection: art3d.line_collection_2d_to_3d(col, zs=zs, zdir=zdir) col.set_sort_zpos(min(zs)) - elif type(col) is collections.PatchCollection: + elif type(col) is mcoll.PatchCollection: art3d.patch_collection_2d_to_3d(col, zs=zs, zdir=zdir) col.set_sort_zpos(min(zs)) From 7023ec3763be53c0949e0a6578421020c78f706c Mon Sep 17 00:00:00 2001 From: Ben Root Date: Thu, 23 Jun 2011 15:53:26 -0500 Subject: [PATCH 013/214] The example 3d plots now appear correctly, however interaction is incredibly insensitive. --- lib/mpl_toolkits/mplot3d/axes3d.py | 32 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 3dbc06e7937c..a57ea046686a 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -91,6 +91,8 @@ def __init__(self, fig, rect=None, *args, **kwargs): if self.zaxis is not None : self._zcid = self.zaxis.callbacks.connect('units finalize', self.relim) + else : + self._zcid = None self._ready = 1 self.mouse_init() @@ -195,7 +197,7 @@ def draw(self, renderer): patch.zorder = i if self._axis3don: - axes = (self.w_xaxis, self.w_yaxis, self.w_zaxis) + axes = (self.xaxis, self.yaxis, self.zaxis) # Draw panes first for ax in axes: ax.draw_pane(renderer) @@ -377,6 +379,12 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True, Note that this function applies to the 3d axes, and as such adds the *scalez* to the function arguments. """ + + self.set_top_view() + if not self._ready: + return + + """ # This method looks at the rectangular volume (see above) # of data and decides how to scale the view portal to fit it. @@ -388,10 +396,6 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True, else: _tight = self._tight = bool(tight) - self.set_top_view() - if not self._ready: - return - Axes.autoscale_view(self, tight=_tight, scalex=scalex, scaley=scaley) if scalez and self._autoscaleZon: @@ -413,16 +417,16 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True, if not _tight: z0, z1 = zlocator.view_limits(z0, z1) self.set_zbound(z0, z1) - + """ # Previous version's code - #if not self.get_autoscale_on(): - # return - #if scalex: - # self.set_xlim3d(self.xy_dataLim.intervalx) - #if scaley: - # self.set_ylim3d(self.xy_dataLim.intervaly) - #if scalez: - # self.set_zlim3d(self.zz_dataLim.intervalx) + if not self.get_autoscale_on(): + return + if scalex: + self.set_xlim3d(self.xy_dataLim.intervalx) + if scaley: + self.set_ylim3d(self.xy_dataLim.intervaly) + if scalez: + self.set_zlim3d(self.zz_dataLim.intervalx) def get_w_lims(self): '''Get 3d world limits.''' From 119b1445589120c40003965465015a757cf9c6a8 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 24 Jun 2011 14:53:01 -0500 Subject: [PATCH 014/214] Fixed interactivity insensitivity regression in mplot3d. Caused by a change in the behavior of get_xlim() and get_ylim() which were originally returning the limits of the pseudo data axes (the original 2d axes), but now the get_xlim() and such return the data limits for the 3d axes. This resulted in incorrect motion deltas for the mouse interactions with the 3d object. --- lib/mpl_toolkits/mplot3d/axes3d.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index a57ea046686a..91a0c6f710aa 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -99,6 +99,10 @@ def __init__(self, fig, rect=None, *args, **kwargs): self.set_top_view() self.axesPatch.set_linewidth(0) + # Calculate the pseudo-data width and height + pseudo_bbox = self.transLimits.inverted().transform([(0, 0), (1, 1)]) + self._pseudo_w, self._pseudo_h = pseudo_bbox[1] - pseudo_bbox[0] + self.figure.add_axes(self) def set_axis_off(self): @@ -844,10 +848,8 @@ def _on_move(self, event): return dx, dy = x - self.sx, y - self.sy - x0, x1 = self.get_xlim() - y0, y1 = self.get_ylim() - w = (x1-x0) - h = (y1-y0) + w = self._pseudo_w + h = self._pseudo_h self.sx, self.sy = x, y # Rotation From 93034659faf6acdbe9d2d274d37bd129700a39d2 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 28 Jun 2011 08:57:00 -0400 Subject: [PATCH 015/214] Remove the need for a fixed set of signal names in the CallbackRegistry --- lib/matplotlib/axes.py | 3 +-- lib/matplotlib/axis.py | 4 ++-- lib/matplotlib/backend_bases.py | 2 +- lib/matplotlib/cbook.py | 33 +++++++++++---------------------- lib/matplotlib/cm.py | 3 +-- lib/matplotlib/figure.py | 4 ++-- 6 files changed, 18 insertions(+), 31 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index 8c30d52444da..c6dd94a9c47e 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -826,8 +826,7 @@ def cla(self): spine.cla() self.ignore_existing_data_limits = True - self.callbacks = cbook.CallbackRegistry(('xlim_changed', - 'ylim_changed')) + self.callbacks = cbook.CallbackRegistry() if self._sharex is not None: # major and minor are class instances with diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index ab9036289f41..df892087590f 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -619,7 +619,7 @@ def __init__(self, axes, pickradius=15): self.axes = axes self.major = Ticker() self.minor = Ticker() - self.callbacks = cbook.CallbackRegistry(('units', 'units finalize')) + self.callbacks = cbook.CallbackRegistry() #class dummy: # locator = None @@ -714,7 +714,7 @@ def cla(self): self.isDefault_label = True # Clear the callback registry for this axis, or it may "leak" - self.callbacks = cbook.CallbackRegistry(('units', 'units finalize')) + self.callbacks = cbook.CallbackRegistry() # whether the grids are on self._gridOnMajor = rcParams['axes.grid'] diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 8e6de9916659..aedb15abe2b4 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1386,7 +1386,7 @@ def __init__(self, figure): figure.set_canvas(self) self.figure = figure # a dictionary from event name to a dictionary that maps cid->func - self.callbacks = cbook.CallbackRegistry(self.events) + self.callbacks = cbook.CallbackRegistry() self.widgetlock = widgets.LockDraw() self._button = None # the button pressed self._key = None # the key pressed diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 04eeefde623f..95d5c0463e76 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -109,15 +109,13 @@ class CallbackRegistry: Handle registering and disconnecting for a set of signals and callbacks:: - signals = 'eat', 'drink', 'be merry' - def oneat(x): print 'eat', x def ondrink(x): print 'drink', x - callbacks = CallbackRegistry(signals) + callbacks = CallbackRegistry() ideat = callbacks.connect('eat', oneat) iddrink = callbacks.connect('drink', ondrink) @@ -208,30 +206,21 @@ def __ne__(self, other): ''' return not self.__eq__(other) - def __init__(self, signals): - '*signals* is a sequence of valid signals' - self.signals = set(signals) - self.callbacks = dict([(s, dict()) for s in signals]) + def __init__(self): + self.callbacks = dict() self._cid = 0 self._func_cid_map = WeakKeyDictionary() - def _check_signal(self, s): - 'make sure *s* is a valid signal or raise a ValueError' - if s not in self.signals: - signals = list(self.signals) - signals.sort() - raise ValueError('Unknown signal "%s"; valid signals are %s'%(s, signals)) - def connect(self, s, func): """ register *func* to be called when a signal *s* is generated func will be called """ - self._check_signal(s) if func in self._func_cid_map: return self._func_cid_map[func] proxy = self.BoundMethodProxy(func) self._cid += 1 + self.callbacks.setdefault(s, dict()) self.callbacks[s][self._cid] = proxy self._func_cid_map[func] = self._cid return self._cid @@ -253,13 +242,13 @@ def process(self, s, *args, **kwargs): process signal *s*. All of the functions registered to receive callbacks on *s* will be called with *\*args* and *\*\*kwargs* """ - self._check_signal(s) - for cid, proxy in self.callbacks[s].items(): - # Clean out dead references - if proxy.inst is not None and proxy.inst() is None: - del self.callbacks[s][cid] - else: - proxy(*args, **kwargs) + if s in self.callbacks: + for cid, proxy in self.callbacks[s].items(): + # Clean out dead references + if proxy.inst is not None and proxy.inst() is None: + del self.callbacks[s][cid] + else: + proxy(*args, **kwargs) class Scheduler(threading.Thread): diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index d89bbeb587fb..9621d345bfb4 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -165,8 +165,7 @@ def __init__(self, norm=None, cmap=None): :mod:`cm` colormap instance, for example :data:`cm.jet` """ - self.callbacksSM = cbook.CallbackRegistry(( - 'changed',)) + self.callbacksSM = cbook.CallbackRegistry() if cmap is None: cmap = get_cmap() if norm is None: norm = colors.Normalize() diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 63e80ad0886b..2ee5c1e7806b 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -247,7 +247,7 @@ def __init__(self, """ Artist.__init__(self) - self.callbacks = cbook.CallbackRegistry(('dpi_changed', )) + self.callbacks = cbook.CallbackRegistry() if figsize is None : figsize = rcParams['figure.figsize'] if dpi is None : dpi = rcParams['figure.dpi'] @@ -777,7 +777,7 @@ def clf(self, keep_observers=False): a gui widget is tracking the axes in the figure. """ self.suppressComposite = None - self.callbacks = cbook.CallbackRegistry(('dpi_changed', )) + self.callbacks = cbook.CallbackRegistry() for ax in tuple(self.axes): # Iterate over the copy. ax.cla() From 8455f68777900465e8419f5abea214724cfd6faa Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 29 Jun 2011 14:00:22 -0400 Subject: [PATCH 016/214] Warn about passing signal names (now deprecated) --- lib/matplotlib/cbook.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 95d5c0463e76..36ffe396fb42 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -206,7 +206,11 @@ def __ne__(self, other): ''' return not self.__eq__(other) - def __init__(self): + def __init__(self, *args): + if len(args): + warnings.warn( + 'CallbackRegistry no longer requires a list of callback types. Ignoring arguments', + DeprecationWarning) self.callbacks = dict() self._cid = 0 self._func_cid_map = WeakKeyDictionary() From 0906cb19c345c235562c86bd5a83df963fe7c5ba Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Wed, 29 Jun 2011 12:03:34 -1000 Subject: [PATCH 017/214] setupext.py: allow linux3 --- setupext.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setupext.py b/setupext.py index b949e22291b0..94e5a0530ac2 100644 --- a/setupext.py +++ b/setupext.py @@ -55,6 +55,7 @@ 'linux2-mips' : ['/usr/local', '/usr'], 'linux2-sparc' : ['/usr/local', '/usr'], 'linux2' : ['/usr/local', '/usr'], + 'linux3' : ['/usr/local', '/usr'], 'linux' : ['/usr/local', '/usr',], 'cygwin' : ['/usr/local', '/usr',], '_darwin' : ['/sw/lib/freetype2', '/sw/lib/freetype219', '/usr/local', From d9ca8ba7d5cf891e97a773f5b7e83280c345bc75 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Wed, 29 Jun 2011 12:34:57 -1000 Subject: [PATCH 018/214] setupext: fix bug in new method of Tcl/Tk discovery Force use of /bin/sh in Popen, and use corresponding shell commands; "source" is a C-shell command, not available in /bin/sh. --- setupext.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setupext.py b/setupext.py index 94e5a0530ac2..e3b12a1977fe 100644 --- a/setupext.py +++ b/setupext.py @@ -932,8 +932,10 @@ def parse_tcl_config(tcl_lib_dir, tk_lib_dir): def get_var(file, varname): p = subprocess.Popen( - 'source %s ; eval echo ${%s}' % (file, varname), - shell=True, stdout=subprocess.PIPE) + '. %s ; eval echo ${%s}' % (file, varname), + shell=True, + executable="/bin/sh", + stdout=subprocess.PIPE) result = p.communicate()[0] return result From 37834164b6ecae083bdb3b169cd4ada8d559cf36 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 30 Jun 2011 13:07:21 -0400 Subject: [PATCH 019/214] Pass ints rather than floats to Tkinter when it expects it. Failure to do so causes exceptions on locales with a non-'.' as a decimal separator. Reported by Hans Bering. --- lib/matplotlib/backends/backend_tkagg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index 7aae9d9016a0..9af5263b286d 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -240,8 +240,8 @@ def resize(self, event): self._tkcanvas.delete(self._tkphoto) self._tkphoto = Tk.PhotoImage( - master=self._tkcanvas, width=width, height=height) - self._tkcanvas.create_image(width/2,height/2,image=self._tkphoto) + master=self._tkcanvas, width=int(width), height=int(height)) + self._tkcanvas.create_image(int(width/2),int(height/2),image=self._tkphoto) self.resize_event() self.show() @@ -555,7 +555,7 @@ def __init__(self, canvas, window): xmin, xmax = canvas.figure.bbox.intervalx height, width = 50, xmax-xmin Tk.Frame.__init__(self, master=self.window, - width=width, height=height, + width=int(width), height=int(height), borderwidth=2) self.update() # Make axes menu @@ -711,7 +711,7 @@ def _init_toolbar(self): xmin, xmax = self.canvas.figure.bbox.intervalx height, width = 50, xmax-xmin Tk.Frame.__init__(self, master=self.window, - width=width, height=height, + width=int(width), height=int(height), borderwidth=2) self.update() # Make axes menu From aaef94485cf71ed3181e0adc5577d1a8911f6544 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 30 Jun 2011 15:31:42 -0400 Subject: [PATCH 020/214] =?UTF-8?q?Fix=20another=20linux3=20bug=20reported?= =?UTF-8?q?=20by=20Tiago=20Rezende=20Campos=20Falc=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/api/font_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/api/font_file.py b/examples/api/font_file.py index 5188f742bd85..495b1905f679 100644 --- a/examples/api/font_file.py +++ b/examples/api/font_file.py @@ -17,7 +17,7 @@ if sys.platform == 'win32': fpath = 'C:\\Windows\\Fonts\\Tahoma.ttf' -elif sys.platform == 'linux2': +elif sys.platform.startswith('linux'): fonts = ['/usr/share/fonts/truetype/freefont/FreeSansBoldOblique.ttf', '/usr/share/fonts/truetype/ttf-liberation/LiberationSans-BoldItalic.ttf', '/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf', From 921ae0675da1d8b2f37dc2334c8cb93a4f739bbd Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Thu, 30 Jun 2011 18:34:47 -1000 Subject: [PATCH 021/214] backend_gtk bug: don't try to destroy a toolbar that is None When rcParams['toolbar'] is "none", the figure manager toolbar attribute becomes None. Only the gtk backend seems not to have been taking this into account. --- lib/matplotlib/backends/backend_gtk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index 142292edd849..e8c22cb1b96c 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -547,14 +547,14 @@ def notify_axes_change(fig): def destroy(self, *args): if _debug: print 'FigureManagerGTK.%s' % fn_name() + if hasattr(self, 'toolbar') and self.toolbar is not None: + self.toolbar.destroy() if hasattr(self, 'vbox'): self.vbox.destroy() if hasattr(self, 'window'): self.window.destroy() if hasattr(self, 'canvas'): self.canvas.destroy() - if hasattr(self, 'toolbar'): - self.toolbar.destroy() self.__dict__.clear() #Is this needed? Other backends don't have it. if Gcf.get_num_fig_managers()==0 and \ From 984d83ed9014588b87a00502e4b5a86b78baf6bb Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sat, 2 Jul 2011 10:33:19 -1000 Subject: [PATCH 022/214] setupext.py: prevent spurious newline in tkagg compilation command --- setupext.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setupext.py b/setupext.py index e3b12a1977fe..70ac6c2125c2 100644 --- a/setupext.py +++ b/setupext.py @@ -939,11 +939,11 @@ def get_var(file, varname): result = p.communicate()[0] return result - tcl_lib_dir = get_var(tcl_config, 'TCL_LIB_SPEC').split()[0][2:] - tcl_inc_dir = get_var(tcl_config, 'TCL_INCLUDE_SPEC')[2:] + tcl_lib_dir = get_var(tcl_config, 'TCL_LIB_SPEC').split()[0][2:].strip() + tcl_inc_dir = get_var(tcl_config, 'TCL_INCLUDE_SPEC')[2:].strip() tcl_lib = get_var(tcl_config, 'TCL_LIB_FLAG')[2:].strip() - tk_lib_dir = get_var(tk_config, 'TK_LIB_SPEC').split()[0][2:] + tk_lib_dir = get_var(tk_config, 'TK_LIB_SPEC').split()[0][2:].strip() tk_inc_dir = get_var(tk_config, 'TK_INCLUDE_SPEC').strip() if tk_inc_dir == '': tk_inc_dir = tcl_inc_dir From 06206a00721ff4f132b17fe8d84e5246789eee8c Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sat, 2 Jul 2011 15:33:31 -1000 Subject: [PATCH 023/214] ticker: overhaul AutoMinorLocator, add optional argument The optional argument allows one to specify the number of minor intervals per major interval. If that number is not specified, the overhaul improves the automated choice of 4 or 5 intervals. For example, a major interval of 10 now yields 5 intervals instead of 4. major_minor_demo2.py was also changed to illustrate the AutoMinorLocator. --- examples/pylab_examples/major_minor_demo2.py | 36 +++++++++------ lib/matplotlib/ticker.py | 48 ++++++++++++++------ 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/examples/pylab_examples/major_minor_demo2.py b/examples/pylab_examples/major_minor_demo2.py index 43de86e24f35..eaeed688ac86 100644 --- a/examples/pylab_examples/major_minor_demo2.py +++ b/examples/pylab_examples/major_minor_demo2.py @@ -1,26 +1,34 @@ #!/usr/bin/env python """ -Set the major ticks on the ints and minor ticks on multiples of 0.2 +Automatic tick selection for major and minor ticks. + +Use interactive pan and zoom to see how the tick intervals +change. There will be either 4 or 5 minor tick intervals +per major interval, depending on the major interval. """ -from pylab import * -from matplotlib.ticker import MultipleLocator, FormatStrFormatter +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.ticker import AutoMinorLocator -majorLocator = MultipleLocator(1) -majorFormatter = FormatStrFormatter('%d') -minorLocator = MultipleLocator(.2) +# One can supply an argument to AutoMinorLocator to +# specify a fixed number of minor intervals per major interval, e.g.: +# minorLocator = AutoMinorLocator(2) +# would lead to a single minor tick between major ticks. +minorLocator = AutoMinorLocator() -t = arange(0.0, 10.0, 0.01) -s = sin(2*pi*t)*exp(-t*0.01) -ax = subplot(111) -plot(t,s) +t = np.arange(0.0, 100.0, 0.01) +s = np.sin(2*np.pi*t)*np.exp(-t*0.01) -ax.xaxis.set_major_locator(majorLocator) -ax.xaxis.set_major_formatter(majorFormatter) +ax = plt.subplot(111) +plt.plot(t,s) -#for the minor ticks, use no labels; default NullFormatter ax.xaxis.set_minor_locator(minorLocator) -show() +plt.tick_params(which='both', width=2) +plt.tick_params(which='major', length=7) +plt.tick_params(which='minor', length=4, color='r') + +plt.show() diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 96607ced29c3..534569c8e07d 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -50,6 +50,13 @@ :class:`MaxNLocator` with simple defaults. This is the default tick locator for most plotting. +:class:`AutoMinorLocator` + locator for minor ticks when the axis is linear and the + major ticks are uniformly spaced. It subdivides the major + tick interval into a specified number of minor intervals, + defaulting to 4 or 5 depending on the major interval. + + There are a number of locators specialized for date locations - see the dates module @@ -1402,6 +1409,16 @@ class AutoMinorLocator(Locator): major ticks. Assumes the scale is linear and major ticks are evenly spaced. """ + def __init__(self, n=None): + """ + *n* is the number of subdivisions of the interval between + major ticks; e.g., n=2 will place a single minor tick midway + between major ticks. + + If *n* is omitted or None, it will be set to 5 or 4. + """ + self.ndivs = n + def __call__(self): 'Return the locations of the ticks' majorlocs = self.axis.get_majorticklocs() @@ -1410,25 +1427,28 @@ def __call__(self): except IndexError: raise ValueError('Need at least two major ticks to find minor ' 'tick locations') - # see whether major step should be divided by 5, 4. This - # should cover most cases. - temp = float(('%e' % majorstep).split('e')[0]) - if temp % 5 < 1e-10: - minorstep = majorstep / 5. + + if self.ndivs is None: + x = int(round(10 ** (np.log10(majorstep) % 1))) + if x in [1, 5, 10]: + ndivs = 5 + else: + ndivs = 4 else: - minorstep = majorstep / 4. + ndivs = self.ndivs + + minorstep = majorstep / ndivs - tmin = majorlocs[0] - majorstep - tmax = majorlocs[-1] + majorstep - locs = np.arange(tmin, tmax, minorstep) vmin, vmax = self.axis.get_view_interval() if vmin > vmax: vmin,vmax = vmax,vmin - locs = locs[(vmin < locs) & (locs < vmax)] - # don't create minor ticks on top of existing major ticks - diff = 0.5 * abs(locs[1] - locs[0]) - locs = [l for l in locs if (np.abs(l - majorlocs) > diff).all()] + t0 = majorlocs[0] + tmin = np.ceil((vmin - t0) / minorstep) * minorstep + tmax = np.floor((vmax - t0) / minorstep) * minorstep + locs = np.arange(tmin, tmax, minorstep) + t0 + cond = np.abs((locs - t0) % majorstep) > minorstep/10.0 + locs = locs.compress(cond) return self.raise_if_exceeds(np.array(locs)) @@ -1495,4 +1515,4 @@ def get_locator(self, d): 'LogFormatterMathtext', 'Locator', 'IndexLocator', 'FixedLocator', 'NullLocator', 'LinearLocator', 'LogLocator', 'AutoLocator', 'MultipleLocator', - 'MaxNLocator', ) + 'MaxNLocator', 'AutoMinorLocator',) From 5f287e128bd9f5bd4928aa5f946a1954d2c5a48c Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Mon, 4 Jul 2011 10:38:59 -1000 Subject: [PATCH 024/214] qt4_compat.py: updated to match ipython 0.11 RC 1. It is based on IPython/external/qt.py. The previous version was based on an earlier version of that file, but fails with the present ipython: http://www.mail-archive.com/matplotlib-devel@lists.sourceforge.net/msg08332.html --- lib/matplotlib/backends/qt4_compat.py | 81 +++++++++++++++------------ 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/lib/matplotlib/backends/qt4_compat.py b/lib/matplotlib/backends/qt4_compat.py index d2993bbba32a..977c50fc9cf7 100644 --- a/lib/matplotlib/backends/qt4_compat.py +++ b/lib/matplotlib/backends/qt4_compat.py @@ -2,60 +2,69 @@ """ import os +import warnings # Available APIs. QT_API_PYQT = 'pyqt' QT_API_PYSIDE = 'pyside' -# Select PyQt4 or PySide using an environment variable, in the same way IPython does. -# IPython is using PyQt as default (for now) so we will too. -QT_API = os.environ.get('QT_API', QT_API_PYQT) +def prepare_pyqt4(): + # For PySide compatibility, use the new-style string API that automatically + # converts QStrings to Unicode Python strings. Also, automatically unpack + # QVariants to their underlying objects. + import sip + sip.setapi('QString', 2) + sip.setapi('QVariant', 2) -if QT_API == QT_API_PYQT: +# Select Qt binding, using the QT_API environment variable if available. +QT_API = os.environ.get('QT_API') +if QT_API is None: try: - from PyQt4 import QtCore, QtGui + import PySide + if PySide.__version_info__ < (1,0,3): + warnings.warn("PySide found with version < 1.0.3; trying PyQt4") + raise ImportError + QT_API = QT_API_PYSIDE except ImportError: - raise ImportError("Qt4 backend requires that PyQt4 is installed.") + try: + prepare_pyqt4() + import PyQt4 + QT_API = QT_API_PYQT + except ImportError: + raise ImportError('Cannot import PySide or PyQt4') + +elif QT_API == QT_API_PYQT: + # Note: This must be called *before* PyQt4 is imported. + prepare_pyqt4() + +# Now perform the imports. +if QT_API == QT_API_PYQT: + from PyQt4 import QtCore, QtGui, QtSvg + # Alias PyQt-specific functions for PySide compatibility. + QtCore.Signal = QtCore.pyqtSignal try: QtCore.Slot = QtCore.pyqtSlot except AttributeError: - QtCore.Slot = pyqtSignature # Not a perfect match but + QtCore.Slot = pyqtSignature # Not a perfect match but # works in simple cases QtCore.Property = QtCore.pyqtProperty __version__ = QtCore.PYQT_VERSION_STR - import sip - try : - if sip.getapi("QString") > 1 : - # Use new getSaveFileNameAndFilter() - _getSaveFileName = lambda self, msg, start, filters, \ - selectedFilter : \ - QtGui.QFileDialog.getSaveFileNameAndFilter( \ - self, msg, start, filters, selectedFilter)[0] - else : - # Use old getSaveFileName() - _getSaveFileName = QtGui.QFileDialog.getSaveFileName - except (AttributeError, KeyError) : - # call to getapi() can fail in older versions of sip - # Use the old getSaveFileName() - _getSaveFileName = QtGui.QFileDialog.getSaveFileName + + # Use new getSaveFileNameAndFilter() + _getSaveFileName = lambda self, msg, start, filters, \ + selectedFilter : \ + QtGui.QFileDialog.getSaveFileNameAndFilter( \ + self, msg, start, filters, selectedFilter)[0] + + elif QT_API == QT_API_PYSIDE: - try: - from PySide import QtCore, QtGui, __version__, __version_info__ - except ImportError: - raise ImportError("Qt4 backend requires that PySide is installed.") + from PySide import QtCore, QtGui, __version__, __version_info__ if __version_info__ < (1,0,3): - raise ImportError("Matplotlib backend_qt4 and backend_qt4agg require PySide >=1.0.3") - - # Alias PySide-specific function for PyQt compatibilty - QtCore.pyqtProperty = QtCore.Property - QtCore.pyqtSignature = QtCore.Slot # Not a perfect match but - # works in simple cases + raise ImportError( + "Matplotlib backend_qt4 and backend_qt4agg require PySide >=1.0.3") - _getSaveFileName = lambda self, msg, start, filters, selectedFilter : \ - QtGui.QFileDialog.getSaveFileName(self, \ - msg, start, filters, selectedFilter)[0] else: raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % - (QT_API, QT_API_PYQT, QT_API_PYSIDE)) \ No newline at end of file + (QT_API, QT_API_PYQT, QT_API_PYSIDE)) From bd245ef1541c27ecc8f67e47f40d9726d24d9acf Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Mon, 4 Jul 2011 11:28:34 -1000 Subject: [PATCH 025/214] qt4_compat and qt4_editor: more pyqt/pyside fixes --- lib/matplotlib/backends/qt4_compat.py | 13 +-- .../backends/qt4_editor/formlayout.py | 90 +++++++++---------- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/lib/matplotlib/backends/qt4_compat.py b/lib/matplotlib/backends/qt4_compat.py index 977c50fc9cf7..95b2042766c1 100644 --- a/lib/matplotlib/backends/qt4_compat.py +++ b/lib/matplotlib/backends/qt4_compat.py @@ -52,12 +52,7 @@ def prepare_pyqt4(): __version__ = QtCore.PYQT_VERSION_STR # Use new getSaveFileNameAndFilter() - _getSaveFileName = lambda self, msg, start, filters, \ - selectedFilter : \ - QtGui.QFileDialog.getSaveFileNameAndFilter( \ - self, msg, start, filters, selectedFilter)[0] - - + _get_save = QtGui.QFileDialog.getSaveFileNameAndFilter elif QT_API == QT_API_PYSIDE: from PySide import QtCore, QtGui, __version__, __version_info__ @@ -65,6 +60,12 @@ def prepare_pyqt4(): raise ImportError( "Matplotlib backend_qt4 and backend_qt4agg require PySide >=1.0.3") + _get_save = QtGui.QFileDialog.getSaveFileName + else: raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % (QT_API, QT_API_PYQT, QT_API_PYSIDE)) + +def _getSaveFileName(self, msg, start, filters, selectedFilter): + return _get_save(self, msg, start, filters, selectedFilter)[0] + diff --git a/lib/matplotlib/backends/qt4_editor/formlayout.py b/lib/matplotlib/backends/qt4_editor/formlayout.py index 740c5234e911..bee116846eda 100644 --- a/lib/matplotlib/backends/qt4_editor/formlayout.py +++ b/lib/matplotlib/backends/qt4_editor/formlayout.py @@ -62,10 +62,10 @@ QtGui.QTabWidget, QtGui.QApplication, QtGui.QStackedWidget, QtGui.QDateEdit, QtGui.QDateTimeEdit, QtGui.QFont, QtGui.QFontComboBox, QtGui.QFontDatabase, QtGui.QGridLayout, QtGui.QFormLayout, QtGui.QDoubleValidator) - + (Qt, SIGNAL, SLOT, QObject, QSize,pyqtSignature, pyqtProperty) =\ -(QtCore.Qt, QtCore.SIGNAL, QtCore.SLOT, QtCore.QObject, QtCore.QSize, - QtCore.pyqtSignature, QtCore.pyqtProperty) +(QtCore.Qt, QtCore.SIGNAL, QtCore.SLOT, QtCore.QObject, QtCore.QSize, + QtCore.Slot, QtCore.Property) import datetime @@ -74,22 +74,22 @@ class ColorButton(QPushButton): Color choosing push button """ __pyqtSignals__ = ("colorChanged(QColor)",) - + def __init__(self, parent=None): QPushButton.__init__(self, parent) self.setFixedSize(20, 20) self.setIconSize(QSize(12, 12)) self.connect(self, SIGNAL("clicked()"), self.choose_color) self._color = QColor() - + def choose_color(self): color = QColorDialog.getColor(self._color,self.parentWidget(),'') if color.isValid(): self.set_color(color) - + def get_color(self): return self._color - + @pyqtSignature("QColor") def set_color(self, color): if color != self._color: @@ -98,7 +98,7 @@ def set_color(self, color): pixmap = QPixmap(self.iconSize()) pixmap.fill(color) self.setIcon(QIcon(pixmap)) - + color = pyqtProperty("QColor", get_color, set_color) @@ -146,11 +146,11 @@ def update_color(self, text): def update_text(self, color): self.lineedit.setText(color.name()) - + def text(self): return self.lineedit.text() - - + + def font_is_installed(font): """Check if font is installed""" return [fam for fam in QFontDatabase().families() if unicode(fam)==font] @@ -184,12 +184,12 @@ def __init__(self, value, parent=None): QGridLayout.__init__(self) font = tuple_to_qfont(value) assert font is not None - + # Font family self.family = QFontComboBox(parent) self.family.setCurrentFont(font) self.addWidget(self.family, 0, 0, 1, -1) - + # Font size self.size = QComboBox(parent) self.size.setEditable(True) @@ -201,17 +201,17 @@ def __init__(self, value, parent=None): self.size.addItems([str(s) for s in sizelist]) self.size.setCurrentIndex(sizelist.index(size)) self.addWidget(self.size, 1, 0) - + # Italic or not self.italic = QCheckBox(self.tr("Italic"), parent) self.italic.setChecked(font.italic()) self.addWidget(self.italic, 1, 1) - + # Bold or not self.bold = QCheckBox(self.tr("Bold"), parent) self.bold.setChecked(font.bold()) self.addWidget(self.bold, 1, 2) - + def get_font(self): font = self.family.currentFont() font.setItalic(self.italic.isChecked()) @@ -223,7 +223,7 @@ def get_font(self): def is_edit_valid(edit): text = edit.text() state = edit.validator().validate(text, 0)[0] - + return state == QDoubleValidator.Acceptable class FormWidget(QWidget): @@ -242,7 +242,7 @@ def __init__(self, data, comment="", parent=None): print "*"*80 print "COMMENT:", comment print "*"*80 - + def get_dialog(self): """Return FormDialog instance""" dialog = self.parent() @@ -315,7 +315,7 @@ def setup(self): field = QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field) - + def get(self): valuelist = [] for index, (label, value) in enumerate(self.data): @@ -356,26 +356,26 @@ def __init__(self, datalist, comment="", parent=None): self.setLayout(layout) self.combobox = QComboBox() layout.addWidget(self.combobox) - + self.stackwidget = QStackedWidget(self) layout.addWidget(self.stackwidget) self.connect(self.combobox, SIGNAL("currentIndexChanged(int)"), self.stackwidget, SLOT("setCurrentIndex(int)")) - + self.widgetlist = [] for data, title, comment in datalist: self.combobox.addItem(title) widget = FormWidget(data, comment=comment, parent=self) self.stackwidget.addWidget(widget) self.widgetlist.append(widget) - + def setup(self): for widget in self.widgetlist: widget.setup() def get(self): return [ widget.get() for widget in self.widgetlist] - + class FormTabWidget(QWidget): def __init__(self, datalist, comment="", parent=None): @@ -393,11 +393,11 @@ def __init__(self, datalist, comment="", parent=None): index = self.tabwidget.addTab(widget, title) self.tabwidget.setTabToolTip(index, comment) self.widgetlist.append(widget) - + def setup(self): for widget in self.widgetlist: widget.setup() - + def get(self): return [ widget.get() for widget in self.widgetlist] @@ -409,7 +409,7 @@ def __init__(self, data, title="", comment="", QDialog.__init__(self, parent) self.apply_callback = apply - + # Form if isinstance(data[0][0], (list, tuple)): self.formwidget = FormTabWidget(data, comment=comment, @@ -418,11 +418,11 @@ def __init__(self, data, title="", comment="", self.formwidget = FormComboWidget(data, comment=comment, parent=self) else: - self.formwidget = FormWidget(data, comment=comment, + self.formwidget = FormWidget(data, comment=comment, parent=self) layout = QVBoxLayout() layout.addWidget(self.formwidget) - + self.float_fields = [] self.formwidget.setup() @@ -439,15 +439,15 @@ def __init__(self, data, title="", comment="", layout.addWidget(bbox) self.setLayout(layout) - + self.setWindowTitle(title) if not isinstance(icon, QIcon): icon = QWidget().style().standardIcon(QStyle.SP_MessageBoxQuestion) self.setWindowIcon(icon) - + def register_float_field(self, field): self.float_fields.append(field) - + def update_buttons(self): valid = True for field in self.float_fields: @@ -457,18 +457,18 @@ def update_buttons(self): btn = self.bbox.button(btn_type) if btn is not None: btn.setEnabled(valid) - + def accept(self): self.data = self.formwidget.get() QDialog.accept(self) - + def reject(self): self.data = None QDialog.reject(self) - + def apply(self): self.apply_callback(self.formwidget.get()) - + def get(self): """Return form result""" return self.data @@ -478,22 +478,22 @@ def fedit(data, title="", comment="", icon=None, parent=None, apply=None): """ Create form dialog and return result (if Cancel button is pressed, return None) - + data: datalist, datagroup title: string comment: string icon: QIcon instance parent: parent QWidget apply: apply callback (function) - + datalist: list/tuple of (field_name, field_value) datagroup: list/tuple of (datalist *or* datagroup, title, comment) - + -> one field for each member of a datalist -> one tab for each member of a top-level datagroup -> one page (of a multipage widget, each page can be selected with a combo box) for each member of a datagroup inside a datagroup - + Supported types for field_value: - int, float, str, unicode, bool - colors: in Qt-compatible text form, i.e. in hex format or name (red,...) @@ -502,12 +502,12 @@ def fedit(data, title="", comment="", icon=None, parent=None, apply=None): * the first element will be the selected index (or value) * the other elements can be couples (key, value) or only values """ - + # Create a QApplication instance if no instance currently exists # (e.g. if the module is used directly from the interpreter) if QApplication.startingUp(): _app = QApplication([]) - + dialog = FormDialog(data, title, comment, icon, parent, apply) if dialog.exec_(): return dialog.get() @@ -531,13 +531,13 @@ def create_datalist_example(): ('date', datetime.date(2010, 10, 10)), ('datetime', datetime.datetime(2010, 10, 10)), ] - + def create_datagroup_example(): datalist = create_datalist_example() return ((datalist, "Category 1", "Category 1 comment"), (datalist, "Category 2", "Category 2 comment"), (datalist, "Category 3", "Category 3 comment")) - + #--------- datalist example datalist = create_datalist_example() def apply_test(data): @@ -545,11 +545,11 @@ def apply_test(data): print "result:", fedit(datalist, title="Example", comment="This is just an .", apply=apply_test) - + #--------- datagroup example datagroup = create_datagroup_example() print "result:", fedit(datagroup, "Global title") - + #--------- datagroup inside a datagroup example datalist = create_datalist_example() datagroup = create_datagroup_example() From a4f22c6e36dca44e9de27c8cf4d794d4093e0639 Mon Sep 17 00:00:00 2001 From: Eric Firing example Date: Mon, 4 Jul 2011 21:20:59 -1000 Subject: [PATCH 026/214] pyqt4/pyside: use rcParams instead of environment variable This provides easier control for the mpl user (keeping configuration in the rc system), uses the most conservative default (PyQt4), and does not alter the API version. --- lib/matplotlib/backends/qt4_compat.py | 56 +++++++++++---------------- lib/matplotlib/rcsetup.py | 2 + matplotlibrc.template | 5 +++ 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/lib/matplotlib/backends/qt4_compat.py b/lib/matplotlib/backends/qt4_compat.py index 95b2042766c1..df623207c320 100644 --- a/lib/matplotlib/backends/qt4_compat.py +++ b/lib/matplotlib/backends/qt4_compat.py @@ -3,39 +3,18 @@ import os import warnings +from matplotlib import rcParams # Available APIs. -QT_API_PYQT = 'pyqt' -QT_API_PYSIDE = 'pyside' +QT_API_PYQT = 'PyQt4' +QT_API_PYSIDE = 'PySide' -def prepare_pyqt4(): - # For PySide compatibility, use the new-style string API that automatically - # converts QStrings to Unicode Python strings. Also, automatically unpack - # QVariants to their underlying objects. - import sip - sip.setapi('QString', 2) - sip.setapi('QVariant', 2) - -# Select Qt binding, using the QT_API environment variable if available. -QT_API = os.environ.get('QT_API') -if QT_API is None: - try: - import PySide - if PySide.__version_info__ < (1,0,3): - warnings.warn("PySide found with version < 1.0.3; trying PyQt4") - raise ImportError - QT_API = QT_API_PYSIDE - except ImportError: - try: - prepare_pyqt4() - import PyQt4 - QT_API = QT_API_PYQT - except ImportError: - raise ImportError('Cannot import PySide or PyQt4') +# Select Qt binding, using the rcParams variable if available. +QT_API = rcParams.setdefault('backend.qt4', QT_API_PYQT) -elif QT_API == QT_API_PYQT: - # Note: This must be called *before* PyQt4 is imported. - prepare_pyqt4() +# We will define an appropriate wrapper for the differing versions +# of file dialog. +_getSaveFileName = None # Now perform the imports. if QT_API == QT_API_PYQT: @@ -51,8 +30,17 @@ def prepare_pyqt4(): QtCore.Property = QtCore.pyqtProperty __version__ = QtCore.PYQT_VERSION_STR - # Use new getSaveFileNameAndFilter() - _get_save = QtGui.QFileDialog.getSaveFileNameAndFilter + import sip + try : + if sip.getapi("QString") > 1 : + # Use new getSaveFileNameAndFilter() + _get_save = QtGui.QFileDialog.getSaveFileNameAndFilter + else : + # Use old getSaveFileName() + _getSaveFileName = QtGui.QFileDialog.getSaveFileName + except (AttributeError, KeyError) : + # call to getapi() can fail in older versions of sip + _getSaveFileName = QtGui.QFileDialog.getSaveFileName elif QT_API == QT_API_PYSIDE: from PySide import QtCore, QtGui, __version__, __version_info__ @@ -66,6 +54,8 @@ def prepare_pyqt4(): raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % (QT_API, QT_API_PYQT, QT_API_PYSIDE)) -def _getSaveFileName(self, msg, start, filters, selectedFilter): - return _get_save(self, msg, start, filters, selectedFilter)[0] +if _getSaveFileName is None: + + def _getSaveFileName(self, msg, start, filters, selectedFilter): + return _get_save(self, msg, start, filters, selectedFilter)[0] diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index ddcf65cfcfd3..3c0095acf034 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -106,6 +106,7 @@ def validate_backend(s): if s.startswith('module://'): return s else: return _validate_standard_backends(s) +validate_qt4 = ValidateInStrings('backend.qt4', ['PyQt4', 'PySide']) validate_toolbar = ValidateInStrings('toolbar',[ 'None','classic','toolbar2', @@ -341,6 +342,7 @@ def __call__(self, s): defaultParams = { 'backend' : ['Agg', validate_backend], # agg is certainly present 'backend_fallback' : [True, validate_bool], # agg is certainly present + 'backend.qt4' : ['PyQt4', validate_qt4], 'toolbar' : ['toolbar2', validate_toolbar], 'datapath' : [None, validate_path_exists], # handled by _get_data_path_cached 'interactive' : [False, validate_bool], diff --git a/matplotlibrc.template b/matplotlibrc.template index 0b76e55b2a45..b00cc5619497 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -30,6 +30,11 @@ # 'module://my_backend' backend : %(backend)s +# If you are using the Qt4Agg backend, you can choose here +# to use the PyQt4 bindings or the newer PySide bindings to +# the underlying Qt4 toolkit. +backend.qt4 : PyQt4 + # if you are runing pyplot inside a GUI and your backend choice # conflicts, we will automatically try and find a compatible one for # you if backend_fallback is True From 06195c35f4348f37002e850d1cee992d07f5a29c Mon Sep 17 00:00:00 2001 From: Maximilian Trescher Date: Wed, 6 Jul 2011 09:25:09 +0200 Subject: [PATCH 027/214] fix for issue #135. Workaround for rounding problems --- lib/matplotlib/dates.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 90183156cc08..43406357f445 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -299,9 +299,15 @@ def drange(dstart, dend, delta): delta.microseconds/MUSECONDS_PER_DAY) f1 = _to_ordinalf(dstart) f2 = _to_ordinalf(dend) - return np.arange(f1, f2, step) - - + + num = int(np.ceil((f2-f1)/step)) #calculate the difference between dend and dstart in times of delta + dinterval_end = dstart + num*delta #calculate end of the interval which will be generated + if dinterval_end >= dend: #ensure, that an half open interval will be generated [dstart, dend) + dinterval_end -= delta #if the endpoint is greated than dend, just subtract one delta + num -= 1 + + f2 = _to_ordinalf(dinterval_end) #new float-endpoint + return np.linspace(f1, f2, num+1) ### date tickers and formatters ### From 9a50214a78b5cdef0d6c0789f477a3b2a40f8dd9 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Wed, 6 Jul 2011 10:15:12 -1000 Subject: [PATCH 028/214] qt_compat.py: support the ETS environment variable QT_API --- lib/matplotlib/backends/qt4_compat.py | 39 +++++++++++++++++++-------- matplotlibrc.template | 10 +++++-- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/backends/qt4_compat.py b/lib/matplotlib/backends/qt4_compat.py index df623207c320..220ef1bb4917 100644 --- a/lib/matplotlib/backends/qt4_compat.py +++ b/lib/matplotlib/backends/qt4_compat.py @@ -6,19 +6,40 @@ from matplotlib import rcParams # Available APIs. -QT_API_PYQT = 'PyQt4' -QT_API_PYSIDE = 'PySide' +QT_API_PYQT = 'PyQt4' # API is not set here; Python 2.x default is V 1 +QT_API_PYQTv2 = 'PyQt4v2' # forced to Version 2 API +QT_API_PYSIDE = 'PySide' # only supports Version 2 API -# Select Qt binding, using the rcParams variable if available. -QT_API = rcParams.setdefault('backend.qt4', QT_API_PYQT) +ETS = dict(pyqt=QT_API_PYQTv2, pyside=QT_API_PYSIDE) + +# If the ETS QT_API environment variable is set, use it. Note that +# ETS requires the version 2 of PyQt4, which is not the platform +# default for Python 2.x. + +QT_API_ENV = os.environ.get('QT_API') +if QT_API_ENV is not None: + try: + QT_API = ETS[QT_API_ENV] + except KeyError: + raise RuntimeError( + 'Unrecognized environment variable %r, valid values are: %r or %r' % + (QT_API_ENV, 'pyqt', 'pyside')) +else: + # No ETS environment, so use rcParams. + QT_API = rcParams['backend.qt4'] # We will define an appropriate wrapper for the differing versions # of file dialog. _getSaveFileName = None # Now perform the imports. -if QT_API == QT_API_PYQT: - from PyQt4 import QtCore, QtGui, QtSvg +if QT_API in (QT_API_PYQT, QT_API_PYQTv2): + import sip + if QT_API == QT_API_PYQTv2: + sip.setapi('QString', 2) + sip.setapi('QVariant', 2) + + from PyQt4 import QtCore, QtGui # Alias PyQt-specific functions for PySide compatibility. QtCore.Signal = QtCore.pyqtSignal @@ -30,7 +51,6 @@ QtCore.Property = QtCore.pyqtProperty __version__ = QtCore.PYQT_VERSION_STR - import sip try : if sip.getapi("QString") > 1 : # Use new getSaveFileNameAndFilter() @@ -42,7 +62,7 @@ # call to getapi() can fail in older versions of sip _getSaveFileName = QtGui.QFileDialog.getSaveFileName -elif QT_API == QT_API_PYSIDE: +else: # can only be pyside from PySide import QtCore, QtGui, __version__, __version_info__ if __version_info__ < (1,0,3): raise ImportError( @@ -50,9 +70,6 @@ _get_save = QtGui.QFileDialog.getSaveFileName -else: - raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % - (QT_API, QT_API_PYQT, QT_API_PYSIDE)) if _getSaveFileName is None: diff --git a/matplotlibrc.template b/matplotlibrc.template index b00cc5619497..03f31910baaf 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -33,12 +33,18 @@ backend : %(backend)s # If you are using the Qt4Agg backend, you can choose here # to use the PyQt4 bindings or the newer PySide bindings to # the underlying Qt4 toolkit. -backend.qt4 : PyQt4 +#backend.qt4 : PyQt4 # PyQt4 | PySide + +# Note that this can be overridden by the environment variable +# QT_API used by Enthought Tool Suite (ETS); valid values are +# "pyqt" and "pyside". The "pyqt" setting has the side effect of +# forcing the use of Version 2 API for QString and QVariant. # if you are runing pyplot inside a GUI and your backend choice -# conflicts, we will automatically try and find a compatible one for +# conflicts, we will automatically try to find a compatible one for # you if backend_fallback is True #backend_fallback: True + #interactive : False #toolbar : toolbar2 # None | classic | toolbar2 #timezone : UTC # a pytz timezone string, eg US/Central or Europe/Paris From 9b95bce03911686a1c8d8bfc65fbaa3076281ec2 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 8 Jul 2011 16:33:39 -0500 Subject: [PATCH 029/214] Major revision of mplot3d documentation, including the addition of a faq. --- doc/mpl_toolkits/mplot3d/api.rst | 24 ++++ doc/mpl_toolkits/mplot3d/faq.rst | 50 ++++++++ doc/mpl_toolkits/mplot3d/index.rst | 9 +- examples/mplot3d/contour3d_demo3.py | 6 +- examples/mplot3d/contourf3d_demo2.py | 11 +- lib/mpl_toolkits/mplot3d/axes3d.py | 165 ++++++++++++++++++++++++--- 6 files changed, 238 insertions(+), 27 deletions(-) create mode 100644 doc/mpl_toolkits/mplot3d/faq.rst diff --git a/doc/mpl_toolkits/mplot3d/api.rst b/doc/mpl_toolkits/mplot3d/api.rst index 2d7d8ee1a720..29d1b6bd1ca5 100644 --- a/doc/mpl_toolkits/mplot3d/api.rst +++ b/doc/mpl_toolkits/mplot3d/api.rst @@ -1,3 +1,5 @@ +.. _toolkit_mplot3d-api: + *********** mplot3d API *********** @@ -5,10 +7,32 @@ mplot3d API :mod:`mpl_toolkits.mplot3d.axes3d` ================================== +.. note:: + Significant effort went into bringing axes3d to feature-parity with + regular axes objects for version 1.1.0. However, more work remains. + Please report any functions that do not behave as expected as a bug. + In addition, help and patches would be greatly appreciated! + .. automodule:: mpl_toolkits.mplot3d.axes3d :members: :show-inheritance: +:mod:`mpl_toolkits.mplot3d.axis3d` +================================== + +.. note:: + Historically, axis3d has suffered from having hard-coded constants + controlling the look and feel of the 3d plot. This precluded user + level adjustments such as label spacing, font colors and panel colors. + For version 1.1.0, these constants have been consolidated into a single + private member dictionary, `self._axinfo`, for the axis object. This is + intended only as a stop-gap measure to allow user-level customization, + but it is not intended to be permanent. + +.. automodule:: mpl_toolkits.mplot3d.axis3d + :members: + :show-inheritance: + :mod:`mpl_toolkits.mplot3d.art3d` ================================= diff --git a/doc/mpl_toolkits/mplot3d/faq.rst b/doc/mpl_toolkits/mplot3d/faq.rst new file mode 100644 index 000000000000..de412385ed52 --- /dev/null +++ b/doc/mpl_toolkits/mplot3d/faq.rst @@ -0,0 +1,50 @@ +.. _toolkit_mplot3d-faq: + +*********** +mplot3d FAQ +*********** + +How is mplot3d different from MayaVi? +===================================== +`MayaVi2 `_ is a very powerful and featureful 3D graphing library. For advanced +3D scenes and excellent rendering capabilities, it is highly recomended to +use MayaVi2. + +mplot3d was intended to allow users to create simple 3D graphs with the same +"look-and-feel" as matplotlib's 2D plots. Furthermore, users can use the same +toolkit that they are already familiar with to generate both their 2D and 3D +plots. + + +My 3D plot doesn't look right at certain viewing angles +======================================================= +This is probably the most commonly reported issue with mplot3d. The problem +is that -- from some viewing angles -- some 3D objects would appear in front +of another object, even though it is physically behind it. This can result in +plots that do not look "physically correct." + +Unfortunately, while some work is being done to reduce the occurance of this +artifact, it is currently an intractable problem, and can not be fully solved +until matplotlib supports 3D graphics rendering at its core. + +The problem occurs due to the reduction of 3D data down to 2D + z-order +scalar. A single value represents the 3rd dimention for all parts of 3D +objects in a collection. Therefore, when the bounding boxes of two collections +intersect, it becomes possible for this artifact to occur. Furthermore, the +intersection of two 3D objects (such as polygons or patches) can not be +rendered properly in matplotlib's 2D rendering engine. + +This problem will likely not be solved until OpenGL support is added to all of +the backends (patches are greatly welcomed). Until then, if you need complex +3D scenes, we recommend using +`MayaVi `_. + + +I don't like how the 3D plot is laid out, how do I change that? +=============================================================== +Historically, mplot3d has suffered from a hard-coding of parameters used +to control visuals such as label spacing, tick length, and grid line width. +Work is being done to eliminate this issue. For matplotlib v1.1.0, there is +a semi-official manner to modify these parameters. See the note for axis3d +in :doc:`_toolkit_mplot3d-api` for more information. + diff --git a/doc/mpl_toolkits/mplot3d/index.rst b/doc/mpl_toolkits/mplot3d/index.rst index 0747365ae908..0cf7750f52c0 100644 --- a/doc/mpl_toolkits/mplot3d/index.rst +++ b/doc/mpl_toolkits/mplot3d/index.rst @@ -8,15 +8,18 @@ mplot3d Matplotlib mplot3d toolkit ========================== The mplot3d toolkit adds simple 3d plotting capabilities to matplotlib by -supplying an axis object that can create a 2d projection of a 3d scene. +supplying an axes object that can create a 2d projection of a 3d scene. The resulting graph will have the same look and feel as regular 2d plots. The interactive backends also provide the ability to rotate and zoom -the 3d scene. +the 3d scene. One can rotate the 3d scene by simply clicking-and-dragging +the scene. Zooming is done by right-clicking the scene and dragging the +mouse up and down. Note that one does not use the zoom button like one +would use for regular 2d plots. .. toctree:: :maxdepth: 2 tutorial.rst api.rst - + faq.rst diff --git a/examples/mplot3d/contour3d_demo3.py b/examples/mplot3d/contour3d_demo3.py index b5d75e65b842..ee6fdac408b2 100644 --- a/examples/mplot3d/contour3d_demo3.py +++ b/examples/mplot3d/contour3d_demo3.py @@ -10,11 +10,11 @@ cset = ax.contour(X, Y, Z, zdir='y', offset=40) ax.set_xlabel('X') -ax.set_xlim3d(-40, 40) +ax.set_xlim(-40, 40) ax.set_ylabel('Y') -ax.set_ylim3d(-40, 40) +ax.set_ylim(-40, 40) ax.set_zlabel('Z') -ax.set_zlim3d(-100, 100) +ax.set_zlim(-100, 100) plt.show() diff --git a/examples/mplot3d/contourf3d_demo2.py b/examples/mplot3d/contourf3d_demo2.py index eb8d23776da3..85e2a4412b4d 100644 --- a/examples/mplot3d/contourf3d_demo2.py +++ b/examples/mplot3d/contourf3d_demo2.py @@ -1,3 +1,8 @@ +""" +.. versionadded:: 1.1.0 + This demo depends on new features added to contourf3d. +""" + from mpl_toolkits.mplot3d import axes3d import matplotlib.pyplot as plt @@ -10,11 +15,11 @@ cset = ax.contourf(X, Y, Z, zdir='y', offset=40) ax.set_xlabel('X') -ax.set_xlim3d(-40, 40) +ax.set_xlim(-40, 40) ax.set_ylabel('Y') -ax.set_ylim3d(-40, 40) +ax.set_ylim(-40, 40) ax.set_zlabel('Z') -ax.set_zlim3d(-100, 100) +ax.set_zlim(-100, 100) plt.show() diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 91a0c6f710aa..862b1b7874e1 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -226,12 +226,18 @@ def update_datalim(self, xys, **kwargs): def get_autoscale_on(self) : """ Get whether autoscaling is applied for all axes on plot commands + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ return Axes.get_autoscale_on(self) and self.get_autoscalez_on() def get_autoscalez_on(self) : """ Get whether autoscaling for the z-axis is applied on plot commands + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ return self._autoscaleZon @@ -240,6 +246,9 @@ def set_autoscale_on(self, b) : Set whether autoscaling is applied on plot commands accepts: [ *True* | *False* ] + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ Axes.set_autoscale_on(self, b) self.set_autoscalez_on(self, b) @@ -249,6 +258,9 @@ def set_autoscalez_on(self, b) : Set whether autoscaling for the z-axis is applied on plot commands accepts: [ *True* | *False* ] + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ self._autoscalez_on = b @@ -260,6 +272,9 @@ def set_zmargin(self, m) : end of that interval before it is used in autoscaling. accepts: float in range 0 to 1 + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ if m < 0 or m > 1 : raise ValueError("margin must be in range 0 to 1") @@ -284,7 +299,7 @@ def margins(self, *args, **kw) : margins(..., tight=False) - All three forms above set the xmargin, ymargin and zmargin + All forms above set the xmargin, ymargin and zmargin parameters. All keyword parameters are optional. A single argument specifies xmargin, ymargin and zmargin. The *tight* parameter is passed to :meth:`autoscale_view`, which is executed after @@ -297,6 +312,9 @@ def margins(self, *args, **kw) : if *xmargin* is not None, then *xmargin* times the X data interval will be added to each end of that interval before it is used in autoscaling. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ if not args and not kw: return self._xmargin, self._ymargin, self._zmargin @@ -335,6 +353,9 @@ def autoscale(self, enable=True, axis='both', tight=None) : Note that this function behaves the same, but for all three axes. Therfore, 'z' can be passed for *axis*, and 'both' applies to all three axes. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ if enable is None: scalex = True @@ -382,12 +403,21 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True, See :meth:`matplotlib.axes.Axes.autoscale_view` for documentation. Note that this function applies to the 3d axes, and as such adds the *scalez* to the function arguments. + + .. versionchanged :: 1.1.0 + Function signature was changed to better match the 2D version. + *tight* is now explicitly a kwarg and placed first. However, + it currently does not do anything. """ self.set_top_view() if not self._ready: return + # TODO: This is nearly the equivalent code from the 2D + # version, but it doesn't seem to work correctly. + # Therefore, we are currently staying with the + # same old behavior. """ # This method looks at the rectangular volume (see above) # of data and decides how to scale the view portal to fit it. @@ -460,6 +490,7 @@ def set_xlim3d(self, *args, **kwargs): return lims set_xlim = set_xlim3d + def set_ylim3d(self, *args, **kwargs): ''' Set 3D y limits. @@ -490,11 +521,19 @@ def get_xlim3d(self): return self.xy_viewLim.intervalx get_xlim3d.__doc__ = maxes.Axes.get_xlim.__doc__ get_xlim = get_xlim3d + get_xlim.__doc__ += """ + .. versionchanged :: 1.1.0 + This function now correctly refers to the 3D x-limits + """ def get_ylim3d(self): return self.xy_viewLim.intervaly get_ylim3d.__doc__ = maxes.Axes.get_ylim.__doc__ get_ylim = get_ylim3d + get_ylim.__doc__ += """ + .. versionchanged :: 1.1.0 + This function now correctly refers to the 3D y-limits. + """ def get_zlim3d(self): '''Get 3D z limits.''' @@ -504,6 +543,9 @@ def get_zlim3d(self): def get_zscale(self) : """ Return the zaxis scale string %s + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ % (", ".join(mscale.get_scale_names())) return self.zaxis.get_scale() @@ -513,13 +555,21 @@ def set_xscale(self, value, **kwargs) : self.xaxis.set_scale(value, **kwargs) self.autoscale_view(scaley=False, scalez=False) self._update_transScale() - set_xscale.__doc__ = maxes.Axes.set_xscale.__doc__ + set_xscale.__doc__ = maxes.Axes.set_xscale.__doc__ + """ + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. + """ def set_yscale(self, value, **kwargs) : self.yaxis.set_scale(value, **kwargs) self.autoscale_view(scalex=False, scalez=False) self._update_transScale() - set_yscale.__doc__ = maxes.Axes.set_yscale.__doc__ + set_yscale.__doc__ = maxes.Axes.set_yscale.__doc__ + """ + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. + """ @docstring.dedent_interpd def set_zscale(self, value, **kwargs) : @@ -539,6 +589,9 @@ def set_zscale(self, value, **kwargs) : Currently, Axes3D objects only supports linear scales. Other scales may or may not work, and support for these is improving with each release. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ self.zaxis.set_scale(value, **kwargs) self.autoscale_view(scalex=False, scaley=False) @@ -549,7 +602,10 @@ def set_zticks(self, *args, **kwargs): Set z-axis tick locations. See :meth:`matplotlib.axes.Axes.set_yticks` for more details. - Note that minor ticks are not supported at this time. + .. note:: + Minor ticks are not supported. + + .. versionadded:: 1.1.0 """ return self.zaxis.set_ticks(*args, **kwargs) @@ -558,13 +614,18 @@ def get_zticks(self, *args, **kwargs): Get the z-axis tick objects. See :meth:`matplotlib.axes.Axes.get_yticks` for more details. - Note that minor ticks are not supported at this time. + .. note:: + Minor ticks are not supported. + + .. versionadded:: 1.1.0 """ return self.zaxis.get_ticks(*args, **kwargs) def get_zmajorticklabels(self) : """ Get the ztick labels as a list of Text instances + + .. versionadded :: 1.1.0 """ return cbook.silent_list('Text zticklabel', self.zaxis.get_majorticklabels()) @@ -574,7 +635,10 @@ def get_zminorticklabels(self) : Get the ztick labels as a list of Text instances .. note:: - Currently, Axes3D objects do not support minor ticks + Minor ticks are not supported. This function was added + only for completeness. + + .. versionadded :: 1.1.0 """ return cbook.silent_list('Text zticklabel', self.zaxis.get_minorticklabels()) @@ -585,7 +649,9 @@ def set_zticklabels(self, *args, **kwargs) : See :meth:`matplotlib.axes.Axes.set_yticklabels` for more details. .. note:: - Currently, minor ticks are not supported by Axes3D objects. + Minor ticks are not supported by Axes3D objects. + + .. versionadded:: 1.1.0 """ return self.zaxis.set_ticklabels(*args, **kwargs) @@ -595,7 +661,9 @@ def get_zticklabels(self, minor=False) : See :meth:`matplotlib.axes.Axes.get_yticklabels` for more details. .. note:: - Minor ticks are not supported at this time in Axes3D objects. + Minor ticks are not supported. + + .. versionadded:: 1.1.0 """ return cbook.silent_list('Text zticklabel', self.zaxis.get_ticklabels(minor=minor)) @@ -611,6 +679,9 @@ def zaxis_date(self, tz=None) : This function is merely provided for completeness. Axes3D objects do not officially support dates for ticks, and so this may or may not work as expected. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ self.zaxis.axis_date(tz) @@ -619,6 +690,8 @@ def get_zticklines(self) : Get ztick lines as a list of Line2D instances. Note that this function is provided merely for completeness. These lines are re-calculated as the display changes. + + .. versionadded:: 1.1.0 """ return self.zaxis.get_ticklines() @@ -885,13 +958,23 @@ def _on_move(self, event): self.figure.canvas.draw() def set_zlabel(self, zlabel, fontdict=None, labelpad=None, **kwargs): - '''Set zlabel. See doc for :meth:`set_xlabel` for description.''' + ''' + Set zlabel. See doc for :meth:`set_ylabel` for description. + + .. note:: + Currently, *labelpad* does not have an effect on the labels. + ''' + # FIXME: With a rework of axis3d.py, the labelpad should work again + # At that point, remove the above message in the docs. if labelpad is not None : self.zaxis.labelpad = labelpad return self.zaxis.set_label_text(zlabel, fontdict, **kwargs) def get_zlabel(self) : """ Get the z-label text string. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ label = self.zaxis.get_label() return label.get_text() @@ -901,6 +984,8 @@ def get_zlabel(self) : def get_frame_on(self): """ Get whether the 3d axes panels are drawn + + .. versionadded :: 1.1.0 """ return self._frameon @@ -909,14 +994,19 @@ def set_frame_on(self, b): Set whether the 3d axes panels are drawn ACCEPTS: [ *True* | *False* ] + + .. versionadded :: 1.1.0 """ - self._frameon = b + self._frameon = bool(b) def get_axisbelow(self): """ Get whether axis below is true or not. For axes3d objects, this will always be *True* + + .. versionadded :: 1.1.0 + This function was added for completeness. """ return True @@ -928,6 +1018,9 @@ def set_axisbelow(self, b): For axes3d objects, this will ignore any settings and just use *True* ACCEPTS: [ *True* | *False* ] + + .. versionadded :: 1.1.0 + This function was added for completeness. """ self._axisbelow = True @@ -935,9 +1028,13 @@ def grid(self, b=True, **kwargs): ''' Set / unset 3D grid. - Currently, this function does not behave the same as - :meth:`matplotlib.axes.Axes.grid`, but it is intended to - eventually support that behavior. + .. note:: + Currently, this function does not behave the same as + :meth:`matplotlib.axes.Axes.grid`, but it is intended to + eventually support that behavior. + + .. versionchanged :: 1.1.0 + This function was changed, but not tested. Please report any bugs. ''' # TODO: Operate on each axes separately if len(kwargs) : @@ -954,6 +1051,9 @@ def ticklabel_format(self, **kwargs) : axes of the Axes3D object. Therefore, the *axis* argument will also accept a value of 'z' and the value of 'both' will apply to all three axes. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ style = kwargs.pop('style', '').lower() scilimits = kwargs.pop('scilimits', None) @@ -1014,6 +1114,9 @@ def locator_params(self, axis='both', tight=None, **kwargs) : parameters being set for all three axes. Also, *axis* can also take a value of 'z' to apply parameters to the z axis. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ _x = axis in ['x', 'both'] _y = axis in ['y', 'both'] @@ -1047,7 +1150,11 @@ def tick_params(self, axis='both', **kwargs) : .. note:: While this function is currently implemented, the core part of the Axes3D object may ignore some of these settings. - Future releases will fix this. + Future releases will fix this. Priority will be given to + those who file bugs. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ Axes.tick_params(self, axis, **kwargs) if axis in ['z', 'both'] : @@ -1061,12 +1168,22 @@ def tick_params(self, axis='both', **kwargs) : ### data limits, ticks, tick labels, and formatting def invert_zaxis(self): - "Invert the z-axis." + """ + Invert the z-axis. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. + """ bottom, top = self.get_zlim() self.set_zlim(top, bottom) def zaxis_inverted(self): - 'Returns True if the z-axis is inverted.' + ''' + Returns True if the z-axis is inverted. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. + ''' bottom, top = self.get_zlim() return top < bottom @@ -1076,6 +1193,8 @@ def get_zbound(self): lowerBound < upperBound + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ bottom, top = self.get_zlim() if bottom < top: @@ -1088,6 +1207,9 @@ def set_zbound(self, lower=None, upper=None): Set the lower and upper numerical bounds of the z-axis. This method will honor axes inversion regardless of parameter order. It will not change the :attr:`_autoscaleZon` attribute. + + .. versionadded :: 1.1.0 + This function was added, but not tested. Please report any bugs. """ if upper is None and iterable(lower): lower,upper = lower @@ -1195,7 +1317,7 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): ============= ================================================ Other arguments are passed on to - :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection.__init__` + :class:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` ''' had_data = self.has_data() @@ -1354,7 +1476,7 @@ def plot_wireframe(self, X, Y, Z, *args, **kwargs): ========== ================================================ Keyword arguments are passed on to - :func:`matplotlib.collections.LineCollection.__init__`. + :class:`~matplotlib.collections.LineCollection`. Returns a :class:`~mpl_toolkits.mplot3d.art3d.Line3DCollection` ''' @@ -1512,6 +1634,8 @@ def tricontour(self, X, Y, Z, *args, **kwargs): :func:`~matplotlib.axes.Axes.tricontour` Returns a :class:`~matplotlib.axes.Axes.contour` + + .. versionadded:: 1.1.0 ''' extend3d = kwargs.pop('extend3d', False) @@ -1546,6 +1670,9 @@ def contourf(self, X, Y, Z, *args, **kwargs): :func:`~matplotlib.axes.Axes.contourf` Returns a :class:`~matplotlib.axes.Axes.contourf` + + .. versionchanged :: 1.1.0 + The *zdir* and *offset* kwargs were added. ''' zdir = kwargs.pop('zdir', 'z') @@ -1582,6 +1709,8 @@ def tricontourf(self, X, Y, Z, offset=None, zdir='z', *args, **kwargs): :func:`~matplotlib.axes.Axes.tricontour` Returns a :class:`~matplotlib.axes.Axes.contour` + + .. versionadded :: 1.1.0 ''' had_data = self.has_data() From 52152ec51e4d5bc4cf999403f59a0d60fdca0cad Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 8 Jul 2011 16:37:03 -0500 Subject: [PATCH 030/214] Don't forget to add entry to the changelog. --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 07eca61726bd..950886aa4245 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2011-07-08 Many functions added to mplot3d.axes3d to bring Axes3D + objects more feature-parity with regular Axes objects. + Significant revisions to the documentation as well. + - BVR + 2011-06-16 Added *bottom* keyword parameter for the stem command. Also, implemented a legend handler for the stem plot. - JJL From c2705d0cf49efa98d2471f684706108a3b6a4f05 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 8 Jul 2011 20:06:57 -0500 Subject: [PATCH 031/214] mplot3d document cleanup and terminology standardizing --- doc/mpl_toolkits/mplot3d/api.rst | 2 +- doc/mpl_toolkits/mplot3d/faq.rst | 7 ++++--- doc/mpl_toolkits/mplot3d/index.rst | 10 +++++----- doc/mpl_toolkits/mplot3d/tutorial.rst | 10 +++++----- lib/mpl_toolkits/mplot3d/axes3d.py | 20 ++++++++++---------- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/doc/mpl_toolkits/mplot3d/api.rst b/doc/mpl_toolkits/mplot3d/api.rst index 29d1b6bd1ca5..dd3c771afdee 100644 --- a/doc/mpl_toolkits/mplot3d/api.rst +++ b/doc/mpl_toolkits/mplot3d/api.rst @@ -22,7 +22,7 @@ mplot3d API .. note:: Historically, axis3d has suffered from having hard-coded constants - controlling the look and feel of the 3d plot. This precluded user + controlling the look and feel of the 3D plot. This precluded user level adjustments such as label spacing, font colors and panel colors. For version 1.1.0, these constants have been consolidated into a single private member dictionary, `self._axinfo`, for the axis object. This is diff --git a/doc/mpl_toolkits/mplot3d/faq.rst b/doc/mpl_toolkits/mplot3d/faq.rst index de412385ed52..2f1f3b46a7e0 100644 --- a/doc/mpl_toolkits/mplot3d/faq.rst +++ b/doc/mpl_toolkits/mplot3d/faq.rst @@ -6,7 +6,8 @@ mplot3d FAQ How is mplot3d different from MayaVi? ===================================== -`MayaVi2 `_ is a very powerful and featureful 3D graphing library. For advanced +`MayaVi2 `_ +is a very powerful and featureful 3D graphing library. For advanced 3D scenes and excellent rendering capabilities, it is highly recomended to use MayaVi2. @@ -19,7 +20,7 @@ plots. My 3D plot doesn't look right at certain viewing angles ======================================================= This is probably the most commonly reported issue with mplot3d. The problem -is that -- from some viewing angles -- some 3D objects would appear in front +is that -- from some viewing angles -- a 3D object would appear in front of another object, even though it is physically behind it. This can result in plots that do not look "physically correct." @@ -28,7 +29,7 @@ artifact, it is currently an intractable problem, and can not be fully solved until matplotlib supports 3D graphics rendering at its core. The problem occurs due to the reduction of 3D data down to 2D + z-order -scalar. A single value represents the 3rd dimention for all parts of 3D +scalar. A single value represents the 3rd dimension for all parts of 3D objects in a collection. Therefore, when the bounding boxes of two collections intersect, it becomes possible for this artifact to occur. Furthermore, the intersection of two 3D objects (such as polygons or patches) can not be diff --git a/doc/mpl_toolkits/mplot3d/index.rst b/doc/mpl_toolkits/mplot3d/index.rst index 0cf7750f52c0..e393b9d2136a 100644 --- a/doc/mpl_toolkits/mplot3d/index.rst +++ b/doc/mpl_toolkits/mplot3d/index.rst @@ -7,15 +7,15 @@ mplot3d Matplotlib mplot3d toolkit ========================== -The mplot3d toolkit adds simple 3d plotting capabilities to matplotlib by -supplying an axes object that can create a 2d projection of a 3d scene. -The resulting graph will have the same look and feel as regular 2d plots. +The mplot3d toolkit adds simple 3D plotting capabilities to matplotlib by +supplying an axes object that can create a 2D projection of a 3D scene. +The resulting graph will have the same look and feel as regular 2D plots. The interactive backends also provide the ability to rotate and zoom -the 3d scene. One can rotate the 3d scene by simply clicking-and-dragging +the 3D scene. One can rotate the 3D scene by simply clicking-and-dragging the scene. Zooming is done by right-clicking the scene and dragging the mouse up and down. Note that one does not use the zoom button like one -would use for regular 2d plots. +would use for regular 2D plots. .. toctree:: :maxdepth: 2 diff --git a/doc/mpl_toolkits/mplot3d/tutorial.rst b/doc/mpl_toolkits/mplot3d/tutorial.rst index 0a0e2a07a1d9..a973647fa60d 100644 --- a/doc/mpl_toolkits/mplot3d/tutorial.rst +++ b/doc/mpl_toolkits/mplot3d/tutorial.rst @@ -22,10 +22,10 @@ add a new axes to it of type :class:`~mpl_toolkits.mplot3d.Axes3D`:: ax = fig.add_subplot(111, projection='3d') .. versionadded:: 1.0.0 - This approach is the preferred method of creating a 3d axes. + This approach is the preferred method of creating a 3D axes. .. note:: - Prior to version 1.0.0, the method of creating a 3d axes was + Prior to version 1.0.0, the method of creating a 3D axes was different. For those using older versions of matplotlib, change ``ax = fig.add_subplot(111, projection='3d')`` to ``ax = Axes3D(fig)``. @@ -121,12 +121,12 @@ Text Subplotting ==================== -Having multiple 3d plots in a single figure is the same -as it is for 2d plots. Also, you can have both 2d and 3d plots +Having multiple 3D plots in a single figure is the same +as it is for 2D plots. Also, you can have both 2D and 3D plots in the same figure. .. versionadded:: 1.0.0 - Subplotting 3d plots was added in v1.0.0. Earlier version can not + Subplotting 3D plots was added in v1.0.0. Earlier version can not do this. .. plot:: mpl_examples/mplot3d/subplot3d_demo.py diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 862b1b7874e1..610b4ce89aab 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -123,7 +123,7 @@ def set_top_view(self): Axes.set_ylim(self, -ydwl, ydw, auto=None) def _init_axis(self): - '''Init 3d axes; overrides creation of regular X/Y axes''' + '''Init 3D axes; overrides creation of regular X/Y axes''' self.w_xaxis = axis3d.XAxis('x', self.xy_viewLim.intervalx, self.xy_dataLim.intervalx, self) self.xaxis = self.w_xaxis @@ -401,7 +401,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True, """ Autoscale the view limits using the data limits. See :meth:`matplotlib.axes.Axes.autoscale_view` for documentation. - Note that this function applies to the 3d axes, and as such + Note that this function applies to the 3D axes, and as such adds the *scalez* to the function arguments. .. versionchanged :: 1.1.0 @@ -463,7 +463,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True, self.set_zlim3d(self.zz_dataLim.intervalx) def get_w_lims(self): - '''Get 3d world limits.''' + '''Get 3D world limits.''' minx, maxx = self.get_xlim3d() miny, maxy = self.get_ylim3d() minz, maxz = self.get_zlim3d() @@ -697,7 +697,7 @@ def get_zticklines(self) : def clabel(self, *args, **kwargs): """ - This function is currently not implemented for 3d axes. + This function is currently not implemented for 3D axes. Returns *None*. """ return None @@ -983,7 +983,7 @@ def get_zlabel(self) : def get_frame_on(self): """ - Get whether the 3d axes panels are drawn + Get whether the 3D axes panels are drawn .. versionadded :: 1.1.0 """ @@ -991,7 +991,7 @@ def get_frame_on(self): def set_frame_on(self, b): """ - Set whether the 3d axes panels are drawn + Set whether the 3D axes panels are drawn ACCEPTS: [ *True* | *False* ] @@ -1257,7 +1257,7 @@ def plot(self, xs, ys, *args, **kwargs): *zs* z value(s), either one for all points or one for each point. *zdir* Which direction to use as z ('x', 'y' or 'z') - when plotting a 2d set. + when plotting a 2D set. ========== ================================================ Other arguments are passed on to @@ -1723,7 +1723,7 @@ def tricontourf(self, X, Y, Z, offset=None, zdir='z', *args, **kwargs): def add_collection3d(self, col, zs=0, zdir='z'): ''' - Add a 3d collection object to the plot. + Add a 3D collection object to the plot. 2D collection types are converted to a 3D version by modifying the object and adding z coordinate information. @@ -1760,7 +1760,7 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', *args, **kwargs): *ys* or a single value to place all points in the same plane. Default is 0. *zdir* Which direction to use as z ('x', 'y' or 'z') - when plotting a 2d set. + when plotting a 2D set. *s* size in points^2. It is a scalar or an array of the same length as *x* and *y*. @@ -1828,7 +1828,7 @@ def bar(self, left, height, zs=0, zdir='z', *args, **kwargs): *zs* Z coordinate of bars, if one value is specified they will all be placed at the same z. *zdir* Which direction to use as z ('x', 'y' or 'z') - when plotting a 2d set. + when plotting a 2D set. ========== ================================================ Keyword arguments are passed onto :func:`~matplotlib.axes.Axes.bar`. From c4f603e5ec5e941c3b30a3d1aa4f4b3aa2af7421 Mon Sep 17 00:00:00 2001 From: Ian Thomas Date: Sun, 10 Jul 2011 16:18:59 +0100 Subject: [PATCH 032/214] Fixed issue #203 --- CHANGELOG | 3 +++ lib/matplotlib/tri/triangulation.py | 26 ++------------------------ lib/matplotlib/tri/tricontour.py | 2 -- lib/matplotlib/tri/tripcolor.py | 2 -- lib/matplotlib/tri/triplot.py | 2 -- 5 files changed, 5 insertions(+), 30 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cf19868f3c98..f105cb6e63f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2011-07-10 Fixed argument handling error in tripcolor/triplot/tricontour, + issue #203. - IMT + 2011-06-28 3D versions of scatter, plot, plot_wireframe, plot_surface, bar3d, and some other functions now support empty inputs. - BVR diff --git a/lib/matplotlib/tri/triangulation.py b/lib/matplotlib/tri/triangulation.py index 5ea1569ecda9..c3062d301684 100644 --- a/lib/matplotlib/tri/triangulation.py +++ b/lib/matplotlib/tri/triangulation.py @@ -141,7 +141,6 @@ def get_from_args_and_kwargs(*args, **kwargs): x = args[0] y = args[1] args = args[2:] # Consumed first two args. - ignore_remaining_args = True # Check triangles in kwargs then args. triangles = kwargs.pop('triangles', None) @@ -161,31 +160,10 @@ def get_from_args_and_kwargs(*args, **kwargs): triangles = None if triangles is not None and from_args: - args = args[1:] # Consumed first item in args. - ignore_remaining_args = False + args = args[1:] # Consumed first item in args. - # Check for mask in kwargs then args. + # Check for mask in kwargs. mask = kwargs.pop('mask', None) - from_args = False - if mask is None and not ignore_remaining_args and len(args) > 0: - mask = args[0] - from_args = True - - if mask is not None: - try: - mask = np.asarray(mask, dtype=np.bool) - except ValueError: - mask = None - - if mask is not None and mask.ndim != 1: - mask = None - - if mask is not None and triangles is not None and \ - len(mask) != triangles.shape[0]: - mask = None - - if mask is not None and from_args: - args = args[1:] # Consumed first item in args. triangulation = Triangulation(x, y, triangles, mask) return triangulation, args, kwargs diff --git a/lib/matplotlib/tri/tricontour.py b/lib/matplotlib/tri/tricontour.py index 92709269893a..2549c45704f8 100644 --- a/lib/matplotlib/tri/tricontour.py +++ b/lib/matplotlib/tri/tricontour.py @@ -109,9 +109,7 @@ def _contour_args(self, args, kwargs): tricontour(x, y, ...) tricontour(x, y, triangles, ...) tricontour(x, y, triangles=triangles, ...) - tricontour(x, y, mask, ...) tricontour(x, y, mask=mask, ...) - tricontour(x, y, triangles, mask, ...) tricontour(x, y, triangles, mask=mask, ...) in which case a Triangulation object will be created. See diff --git a/lib/matplotlib/tri/tripcolor.py b/lib/matplotlib/tri/tripcolor.py index 7c36ae6e780f..2748cd0a4fc5 100644 --- a/lib/matplotlib/tri/tripcolor.py +++ b/lib/matplotlib/tri/tripcolor.py @@ -20,9 +20,7 @@ def tripcolor(ax, *args, **kwargs): tripcolor(x, y, ...) tripcolor(x, y, triangles, ...) tripcolor(x, y, triangles=triangles, ...) - tripcolor(x, y, mask, ...) tripcolor(x, y, mask=mask, ...) - tripcolor(x, y, triangles, mask, ...) tripcolor(x, y, triangles, mask=mask, ...) in which case a Triangulation object will be created. See diff --git a/lib/matplotlib/tri/triplot.py b/lib/matplotlib/tri/triplot.py index 5702e3459c2e..cdd5cb3427df 100644 --- a/lib/matplotlib/tri/triplot.py +++ b/lib/matplotlib/tri/triplot.py @@ -22,9 +22,7 @@ def triplot(ax, *args, **kwargs): triplot(x, y, ...) triplot(x, y, triangles, ...) triplot(x, y, triangles=triangles, ...) - triplot(x, y, mask, ...) triplot(x, y, mask=mask, ...) - triplot(x, y, triangles, mask, ...) triplot(x, y, triangles, mask=mask, ...) in which case a Triangulation object will be created. See From f672b59751efbd6fb8496f0c4d0d3d6693c2b94b Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sun, 10 Jul 2011 16:45:25 -0500 Subject: [PATCH 033/214] Some more expansion and cleanup of mplot3d docs and examples Also slightly tweaked the tick label and axis label spacing for improved visualization --- doc/_static/demo_mplot3d.png | Bin 0 -> 43263 bytes doc/mpl_toolkits/mplot3d/api.rst | 28 ++++++++++++++++++++-------- doc/mpl_toolkits/mplot3d/faq.rst | 5 +++-- doc/mpl_toolkits/mplot3d/index.rst | 2 ++ examples/mplot3d/surface3d_demo.py | 8 ++++---- examples/mplot3d/surface3d_demo3.py | 3 +-- lib/mpl_toolkits/mplot3d/axis3d.py | 4 ++-- 7 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 doc/_static/demo_mplot3d.png diff --git a/doc/_static/demo_mplot3d.png b/doc/_static/demo_mplot3d.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d9b77240f8908f5791fb04c1163e19e0ebc943 GIT binary patch literal 43263 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 C5_swW literal 0 HcmV?d00001 diff --git a/doc/mpl_toolkits/mplot3d/api.rst b/doc/mpl_toolkits/mplot3d/api.rst index dd3c771afdee..b274621439ee 100644 --- a/doc/mpl_toolkits/mplot3d/api.rst +++ b/doc/mpl_toolkits/mplot3d/api.rst @@ -3,9 +3,13 @@ *********** mplot3d API *********** +.. contents:: + :backlinks: none -:mod:`mpl_toolkits.mplot3d.axes3d` -================================== +.. _toolkit_mplot3d-axesapi: + +:mod:`~mpl_toolkits.mplot3d.axes3d` +=================================== .. note:: Significant effort went into bringing axes3d to feature-parity with @@ -17,8 +21,11 @@ mplot3d API :members: :show-inheritance: -:mod:`mpl_toolkits.mplot3d.axis3d` -================================== + +.. _toolkit_mplot3d-axisapi: + +:mod:`~mpl_toolkits.mplot3d.axis3d` +=================================== .. note:: Historically, axis3d has suffered from having hard-coded constants @@ -33,16 +40,21 @@ mplot3d API :members: :show-inheritance: -:mod:`mpl_toolkits.mplot3d.art3d` -================================= +.. _toolkit_mplot3d-artapi: + +:mod:`~mpl_toolkits.mplot3d.art3d` +================================== .. automodule:: mpl_toolkits.mplot3d.art3d :members: :show-inheritance: -:mod:`mpl_toolkits.mplot3d.proj3d` -================================== +.. _toolkit_mplot3d-projapi: + +:mod:`~mpl_toolkits.mplot3d.proj3d` +=================================== .. automodule:: mpl_toolkits.mplot3d.proj3d :members: :show-inheritance: + diff --git a/doc/mpl_toolkits/mplot3d/faq.rst b/doc/mpl_toolkits/mplot3d/faq.rst index 2f1f3b46a7e0..625e2315b4d0 100644 --- a/doc/mpl_toolkits/mplot3d/faq.rst +++ b/doc/mpl_toolkits/mplot3d/faq.rst @@ -46,6 +46,7 @@ I don't like how the 3D plot is laid out, how do I change that? Historically, mplot3d has suffered from a hard-coding of parameters used to control visuals such as label spacing, tick length, and grid line width. Work is being done to eliminate this issue. For matplotlib v1.1.0, there is -a semi-official manner to modify these parameters. See the note for axis3d -in :doc:`_toolkit_mplot3d-api` for more information. +a semi-official manner to modify these parameters. See the note in the +:ref:`toolkit_mplot3d-axisapi` section of the mplot3d API documentation for +more information. diff --git a/doc/mpl_toolkits/mplot3d/index.rst b/doc/mpl_toolkits/mplot3d/index.rst index e393b9d2136a..e5a7bed878be 100644 --- a/doc/mpl_toolkits/mplot3d/index.rst +++ b/doc/mpl_toolkits/mplot3d/index.rst @@ -11,6 +11,8 @@ The mplot3d toolkit adds simple 3D plotting capabilities to matplotlib by supplying an axes object that can create a 2D projection of a 3D scene. The resulting graph will have the same look and feel as regular 2D plots. +.. image:: ../../_static/demo_mplot3d.png + The interactive backends also provide the ability to rotate and zoom the 3D scene. One can rotate the 3D scene by simply clicking-and-dragging the scene. Zooming is done by right-clicking the scene and dragging the diff --git a/examples/mplot3d/surface3d_demo.py b/examples/mplot3d/surface3d_demo.py index 301ee1162a51..fa14700d18cf 100644 --- a/examples/mplot3d/surface3d_demo.py +++ b/examples/mplot3d/surface3d_demo.py @@ -1,6 +1,6 @@ from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm -from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter +from matplotlib.ticker import LinearLocator, FormatStrFormatter import matplotlib.pyplot as plt import numpy as np @@ -13,10 +13,10 @@ Z = np.sin(R) surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False) -ax.set_zlim3d(-1.01, 1.01) +ax.set_zlim(-1.01, 1.01) -ax.w_zaxis.set_major_locator(LinearLocator(10)) -ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f')) +ax.zaxis.set_major_locator(LinearLocator(10)) +ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f')) fig.colorbar(surf, shrink=0.5, aspect=5) diff --git a/examples/mplot3d/surface3d_demo3.py b/examples/mplot3d/surface3d_demo3.py index e1c790da50f0..5d4038f94383 100644 --- a/examples/mplot3d/surface3d_demo3.py +++ b/examples/mplot3d/surface3d_demo3.py @@ -1,6 +1,6 @@ from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm -from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter +from matplotlib.ticker import LinearLocator import matplotlib.pyplot as plt import numpy as np @@ -25,7 +25,6 @@ ax.set_zlim3d(-1, 1) ax.w_zaxis.set_major_locator(LinearLocator(6)) -ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f')) plt.show() diff --git a/lib/mpl_toolkits/mplot3d/axis3d.py b/lib/mpl_toolkits/mplot3d/axis3d.py index 625605b6a607..368f72bfa030 100644 --- a/lib/mpl_toolkits/mplot3d/axis3d.py +++ b/lib/mpl_toolkits/mplot3d/axis3d.py @@ -75,12 +75,12 @@ def __init__(self, adir, v_intervalx, d_intervalx, axes, *args, **kwargs): # This is a temporary member variable. # Do not depend on this existing in future releases! self._axinfo = self._AXINFO[adir].copy() - self._axinfo.update({'label' : {'space_factor': 1.3, + self._axinfo.update({'label' : {'space_factor': 1.6, 'va': 'center', 'ha': 'center'}, 'tick' : {'inward_factor': 0.2, 'outward_factor': 0.1}, - 'ticklabel': {'space_factor': 0.6}, + 'ticklabel': {'space_factor': 0.7}, 'axisline': {'linewidth': 0.75, 'color': (0, 0, 0, 1)}, 'grid' : {'color': (0.9, 0.9, 0.9, 1), From 9bb3520e387f7e253d66693324e0c53f85f7c970 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sun, 10 Jul 2011 17:32:00 -0500 Subject: [PATCH 034/214] plot_surface now supports any array-like input. Closes #181 Also fixed an un-noticed issue with tricontourf. --- lib/mpl_toolkits/mplot3d/axes3d.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 17830aed19ad..267beb9f9f24 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -1316,7 +1316,7 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): ============= ================================================ Argument Description ============= ================================================ - *X*, *Y*, *Z* Data values as numpy.arrays + *X*, *Y*, *Z* Data values as 2D arrays *rstride* Array row stride (step size) *cstride* Array column stride (step size) *color* Color of the surface patches @@ -1334,7 +1334,17 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): had_data = self.has_data() + Z = np.atleast_2d(Z) rows, cols = Z.shape + # TODO: Support masked arrays + X = np.asarray(X) + Y = np.asarray(Y) + # Force X and Y to take the same shape. + # If they can not be fitted to that shape, + # then an exception is automatically thrown. + X.shape = (rows, cols) + Y.shape = (rows, cols) + rstride = kwargs.pop('rstride', 10) cstride = kwargs.pop('cstride', 10) @@ -1481,7 +1491,7 @@ def plot_wireframe(self, X, Y, Z, *args, **kwargs): ========== ================================================ Argument Description ========== ================================================ - *X*, *Y*, Data values as numpy.arrays + *X*, *Y*, Data values as 2D arrays *Z* *rstride* Array row stride (step size) *cstride* Array column stride (step size) @@ -1735,8 +1745,6 @@ def tricontourf(self, X, Y, Z, offset=None, zdir='z', *args, **kwargs): ========== ================================================ *X*, *Y*, Data values as numpy.arrays *Z* - *extend3d* Whether to extend contour in 3D (default: False) - *stride* Stride (step size) for extending contour *zdir* The direction to use: x, y or z (default) *offset* If specified plot a projection of the contour lines on this position in plane normal to zdir @@ -1749,9 +1757,12 @@ def tricontourf(self, X, Y, Z, offset=None, zdir='z', *args, **kwargs): .. versionadded :: 1.1.0 ''' + zdir = kwargs.pop('zdir', 'z') + offset = kwargs.pop('offset', None) had_data = self.has_data() + jX, jY, jZ = art3d.rotate_axes(X, Y, Z, zdir) cset = Axes.tricontourf(self, X, Y, Z, *args, **kwargs) self.add_contourf_set(cset, zdir, offset) From 3dd84af0bc52adae1d0f5a7b14c15f8d513da606 Mon Sep 17 00:00:00 2001 From: Maximilian Trescher Date: Tue, 12 Jul 2011 10:13:35 +0200 Subject: [PATCH 035/214] Added test fpr drange --- lib/matplotlib/tests/test_dates.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index 43854ea4a6ab..bf1d5129beaa 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -2,7 +2,7 @@ import numpy as np from matplotlib.testing.decorators import image_comparison, knownfailureif, cleanup import matplotlib.pyplot as plt -from nose.tools import assert_raises +from nose.tools import assert_raises, assert_equal @image_comparison(baseline_images=['date_empty']) def test_date_empty(): @@ -132,6 +132,31 @@ def test_DateFormatter(): ax.autoscale_view() fig.autofmt_xdate() +def test_drange(): + '''This test should check if drange works as expected, and if all the rounding errors + are fixed''' + from matplotlib import dates + start = datetime.datetime(2011, 1,1, tzinfo=dates.UTC) + end = datetime.datetime(2011, 1, 2, tzinfo=dates.UTC) + delta = datetime.timedelta(hours=1) + #We expect 24 values in drange(start, end, delta), because drange returns dates from + #an half open interval [start, end) + assert_equal(24, len(dates.drange(start, end, delta))) + + #if end is a little bit later, we expect the range to contain one element more + end = end +datetime.timedelta(microseconds=1) + assert_equal(25, len(dates.drange(start, end, delta))) + + #reset end + end = datetime.datetime(2011, 1, 2, tzinfo=dates.UTC) + + #and tst drange with "complicated" floats: + # 4 hours = 1/6 day, this is an "dangerous" float + delta = datetime.timedelta(hours=4) + daterange = dates.drange(start, end, delta) + assert_equal(6, len(daterange)) + assert_equal(dates.num2date(daterange[-1]), end-delta) + #@image_comparison(baseline_images=['empty_date_bug']) @cleanup @knownfailureif(True) From fcd9fd899f1bff24ba0a5f7c523594c030345ed2 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Thu, 14 Jul 2011 11:12:51 -0500 Subject: [PATCH 036/214] Added a "can_pan()" function and included it in the generic panning logic. Also added the function to the geo, polar, and mplot3d axes with the appropriate return values. This closes issue #110. --- lib/matplotlib/axes.py | 6 ++++++ lib/matplotlib/backend_bases.py | 3 ++- lib/matplotlib/projections/geo.py | 6 ++++++ lib/matplotlib/projections/polar.py | 6 ++++++ lib/mpl_toolkits/mplot3d/axes3d.py | 3 +++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index c6dd94a9c47e..f192e2471022 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2781,6 +2781,12 @@ def can_zoom(self): """ return True + def can_pan(self) : + """ + Return *True* if this axes support the pan action + """ + return True + def get_navigate(self): """ Get whether the axes responds to navigation commands diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index aedb15abe2b4..620f24e006cd 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2512,7 +2512,8 @@ def press_pan(self, event): self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): - if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): + if x is not None and y is not None and a.in_axes(event) \ + and a.get_navigate() and a.can_pan() : a.start_pan(x, y, event.button) self._xypress.append((a, i)) self.canvas.mpl_disconnect(self._idDrag) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 84a21c947060..37933dcd2caf 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -222,6 +222,12 @@ def can_zoom(self): """ return False + def can_pan(self) : + """ + Return True if this axes support the pan action + """ + return False + def start_pan(self, x, y, button): pass diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index c4589040574a..6a6902a72c39 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -576,6 +576,12 @@ def can_zoom(self): """ return False + def can_pan(self) : + """ + Return True if this axes support the pan action + """ + return True + def start_pan(self, x, y, button): angle = self._r_label1_position.to_values()[4] / 180.0 * np.pi mode = '' diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 267beb9f9f24..9045e2974b35 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -808,6 +808,9 @@ def mouse_init(self, rotate_btn=1, zoom_btn=3): def can_zoom(self) : return False + def can_pan(self) : + return False + def cla(self): """Clear axes and disable mouse button callbacks. """ From b93fc8f6479429df70d21f9bb865f5fc5efaf673 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 14 Jul 2011 15:45:57 -0400 Subject: [PATCH 037/214] First step in marker refactoring. Create new marker class and reimplement Line2D-based markers in terms of it. --- lib/matplotlib/lines.py | 774 +------- lib/matplotlib/markers.py | 499 +++++ .../baseline_images/test_axes/markevery.pdf | Bin 13630 -> 13652 bytes .../baseline_images/test_axes/markevery.png | Bin 33561 -> 33511 bytes .../baseline_images/test_axes/markevery.svg | 627 +++--- .../test_axes/markevery_line.pdf | Bin 15141 -> 15165 bytes .../test_axes/markevery_line.png | Bin 49782 -> 49689 bytes .../test_axes/markevery_line.svg | 615 +++--- .../test_axes/single_point.pdf | Bin 7011 -> 7007 bytes .../test_axes/single_point.png | Bin 26316 -> 26381 bytes .../test_axes/single_point.svg | 1761 +++++++++++------ src/_backend_agg.cpp | 4 +- 12 files changed, 2445 insertions(+), 1835 deletions(-) create mode 100644 lib/matplotlib/markers.py diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 75ed92702632..18c906ae22f1 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -21,11 +21,11 @@ from artist import allow_rasterization from matplotlib import docstring from matplotlib.font_manager import FontProperties - -# special-purpose marker identifiers: -(TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, - CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) - +from matplotlib.markers import MarkerStyle +# Imported here for backward compatibility, even though they don't +# really belong. +from matplotlib.markers import TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, \ + CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN def segment_hits(cx, cy, x, y, radius): """ @@ -103,47 +103,6 @@ class Line2D(Artist): # Need a list ordered with long names first: drawStyleKeys = _drawStyles_l.keys() + _drawStyles_s.keys() - markers = _markers = { # hidden names deprecated - '.' : '_draw_point', - ',' : '_draw_pixel', - 'o' : '_draw_circle', - 'v' : '_draw_triangle_down', - '^' : '_draw_triangle_up', - '<' : '_draw_triangle_left', - '>' : '_draw_triangle_right', - '1' : '_draw_tri_down', - '2' : '_draw_tri_up', - '3' : '_draw_tri_left', - '4' : '_draw_tri_right', - 's' : '_draw_square', - 'p' : '_draw_pentagon', - '*' : '_draw_star', - 'h' : '_draw_hexagon1', - 'H' : '_draw_hexagon2', - '+' : '_draw_plus', - 'x' : '_draw_x', - 'D' : '_draw_diamond', - 'd' : '_draw_thin_diamond', - '|' : '_draw_vline', - '_' : '_draw_hline', - TICKLEFT : '_draw_tickleft', - TICKRIGHT : '_draw_tickright', - TICKUP : '_draw_tickup', - TICKDOWN : '_draw_tickdown', - CARETLEFT : '_draw_caretleft', - CARETRIGHT : '_draw_caretright', - CARETUP : '_draw_caretup', - CARETDOWN : '_draw_caretdown', - 'None' : '_draw_nothing', - ' ' : '_draw_nothing', - '' : '_draw_nothing', - } - - filled_markers = ('o', '^', 'v', '<', '>', - 's', 'd', 'D', 'h', 'H', 'p', '*') - - fillStyles = ('full', 'left' , 'right' , 'bottom' , 'top') - zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') @@ -227,6 +186,7 @@ def __init__(self, xdata, ydata, self.set_drawstyle(drawstyle) self.set_linewidth(linewidth) self.set_color(color) + self._marker = MarkerStyle() self.set_marker(marker) self.set_markevery(markevery) self.set_antialiased(antialiased) @@ -240,8 +200,6 @@ def __init__(self, xdata, ydata, self.set_markeredgewidth(markeredgewidth) self.set_fillstyle(fillstyle) - self._point_size_reduction = 0.5 - self.verticalOffset = None # update kwargs before updating data to give the caller a @@ -336,7 +294,7 @@ def get_fillstyle(self): """ return the marker fillstyle """ - return self._fillstyle + return self._marker.get_fillstyle() def set_fillstyle(self, fs): """ @@ -345,8 +303,7 @@ def set_fillstyle(self, fs): ACCEPTS: ['full' | 'left' | 'right' | 'bottom' | 'top'] """ - assert fs in self.fillStyles - self._fillstyle = fs + self._marker.set_fillstyle(fs) def set_markevery(self, every): """ @@ -390,7 +347,7 @@ def get_window_extent(self, renderer): bbox.update_from_data_xy(self.get_transform().transform(self.get_xydata()), ignore=True) # correct for marker size, if any - if self._marker is not None: + if self._marker: ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 bbox = bbox.padded(ms) return bbox @@ -542,34 +499,53 @@ def draw(self, renderer): drawFunc = getattr(self, funcname) drawFunc(renderer, gc, tpath, affine.frozen()) - if self._marker is not None: + if self._marker: gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self.get_markeredgecolor()) gc.set_linewidth(self._markeredgewidth) gc.set_alpha(self._alpha) - funcname = self._markerFunc - if funcname != '_draw_nothing': - tpath, affine = self._transformed_path.get_transformed_points_and_affine() - if len(tpath.vertices): - # subsample the markers if markevery is not None - markevery = self.get_markevery() - if markevery is not None: - if iterable(markevery): - startind, stride = markevery - else: - startind, stride = 0, markevery - if tpath.codes is not None: - codes = tpath.codes[startind::stride] - else: - codes = None - vertices = tpath.vertices[startind::stride] - subsampled = Path(vertices, codes) + marker = self._marker + tpath, affine = self._transformed_path.get_transformed_points_and_affine() + if len(tpath.vertices): + # subsample the markers if markevery is not None + markevery = self.get_markevery() + if markevery is not None: + if iterable(markevery): + startind, stride = markevery else: - subsampled = tpath - - markerFunc = getattr(self, funcname) - markerFunc(renderer, gc, subsampled, affine.frozen()) + startind, stride = 0, markevery + if tpath.codes is not None: + codes = tpath.codes[startind::stride] + else: + codes = None + vertices = tpath.vertices[startind::stride] + subsampled = Path(vertices, codes) + else: + subsampled = tpath + + snap = marker.get_snap_threshold() + if type(snap) == float: + snap = renderer.points_to_pixels(self._markersize) >= snap + gc.set_snap(snap) + marker_path = marker.get_path() + marker_trans = marker.get_transform() + w = renderer.points_to_pixels(self._markersize) + if marker.get_marker() != ',': # Don't scale for pixels + marker_trans = marker_trans.scale(w) + rgbFace = self._get_rgb_face() + renderer.draw_markers( + gc, marker_path, marker_trans, subsampled, affine.frozen(), + rgbFace) + alt_marker_path = marker.get_alt_path() + if alt_marker_path: + alt_marker_trans = marker.get_alt_transform() + alt_marker_trans = alt_marker_trans.scale(w) + rgbFace = self._get_rgb_face(alt=True) + renderer.draw_markers( + gc, alt_marker_path, alt_marker_trans, subsampled, + affine.frozen(), rgbFace) + gc.restore() gc.restore() @@ -586,8 +562,7 @@ def get_marker(self): return self._marker def get_markeredgecolor(self): if (is_string_like(self._markeredgecolor) and self._markeredgecolor == 'auto'): - if (self._marker in self.filled_markers or - is_math_text(self._marker)): + if self._marker.is_filled(): return 'k' else: return self._color @@ -759,67 +734,14 @@ def set_marker(self, marker): """ Set the line marker - =========== =================================== - marker description - =========== =================================== - ``'.'`` point - ``','`` pixel - ``'o'`` circle - ``'v'`` triangle_down - ``'^'`` triangle_up - ``'<'`` triangle_left - ``'>'`` triangle_right - ``'1'`` tri_down - ``'2'`` tri_up - ``'3'`` tri_left - ``'4'`` tri_right - ``'s'`` square - ``'p'`` pentagon - ``'*'`` star - ``'h'`` hexagon1 - ``'H'`` hexagon2 - ``'+'`` plus - ``'x'`` x - ``'D'`` diamond - ``'d'`` thin_diamond - ``'|'`` vline - ``'_'`` hline - TICKLEFT tickleft - TICKRIGHT tickright - TICKUP tickup - TICKDOWN tickdown - CARETLEFT caretleft - CARETRIGHT caretright - CARETUP caretup - CARETDOWN caretdown - ``'None'`` nothing - ``' '`` nothing - ``''`` nothing - ``'$...$'`` render the string using mathtext - =========== =================================== - - - - ACCEPTS: [ ``'+'`` | ``'*'`` | ``','`` | ``'.'`` - | ``'1'`` | ``'2'`` | ``'3'`` | ``'4'`` - | ``'<'`` | ``'>'`` | ``'D'`` | ``'H'`` - | ``'^'`` | ``'_'`` | ``'d'`` | ``'h'`` - | ``'o'`` | ``'p'`` | ``'s'`` | ``'v'`` - | ``'x'`` | ``'|'`` - | TICKUP | TICKDOWN | TICKLEFT | TICKRIGHT - | CARETUP | CARETDOWN | CARETLEFT | CARETRIGHT - | ``'None'`` | ``' '`` | ``''`` | ``'$...$'`` ] - - """ - if marker in self._markers: - self._marker = marker - self._markerFunc = self._markers[marker] - elif is_math_text(marker): - self._marker = marker - self._markerFunc = '_draw_mathtext_path' - else: #already handle ' ', '' in marker list - verbose.report('Unrecognized marker style %s, %s' % - (marker, type(marker))) + %s + + %s + """ % (MarkerStyle.style_table, MarkerStyle.accepts) + try: + self._marker.set_marker(marker) + except ValueError as e: + verbose.report(str(e)) def set_markeredgecolor(self, ec): """ @@ -908,39 +830,6 @@ def _draw_lines(self, renderer, gc, path, trans): self._lineFunc(renderer, gc, path, trans) - def _draw_mathtext_path(self, renderer, gc, path, trans): - """ - Draws mathtext markers '$...$' using TextPath object. - - Submitted by tcb - """ - from matplotlib.patches import PathPatch - from matplotlib.text import TextPath - - gc.set_snap(False) - - # again, the properties could be initialised just once outside - # this function - # Font size is irrelevant here, it will be rescaled based on - # the drawn size later - props = FontProperties(size=1.0) - text = TextPath(xy=(0,0), s=self.get_marker(), fontproperties=props, - usetex=rcParams['text.usetex']) - if len(text.vertices) == 0: - return - xmin, ymin = text.vertices.min(axis=0) - xmax, ymax = text.vertices.max(axis=0) - width = xmax - xmin - height = ymax - ymin - max_dim = max(width, height) - path_trans = Affine2D() \ - .translate(-xmin + 0.5 * -width, -ymin + 0.5 * -height) \ - .scale((renderer.points_to_pixels(self.get_markersize()) / max_dim)) - - rgbFace = self._get_rgb_face() - renderer.draw_markers(gc, text, path_trans, path, trans, rgbFace) - - def _draw_steps_pre(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) @@ -980,10 +869,6 @@ def _draw_steps_mid(self, renderer, gc, path, trans): self._lineFunc(renderer, gc, path, IdentityTransform()) - def _draw_nothing(self, *args, **kwargs): - pass - - def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle('solid') renderer.draw_path(gc, path, trans) @@ -1007,538 +892,6 @@ def _draw_dotted(self, renderer, gc, path, trans): renderer.draw_path(gc, path, trans) - def _draw_point(self, renderer, gc, path, path_trans): - # just like _draw_circle - gc.set_snap(renderer.points_to_pixels(self._markersize) > 3.0) - w = renderer.points_to_pixels(self._markersize) * \ - self._point_size_reduction * 0.5 - transform = Affine2D().scale(w) - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - if fs=='full': - renderer.draw_markers( - gc, Path.unit_circle(), transform, path, path_trans, rgbFace) - else: - rgbFace_alt = self._get_rgb_face(alt=True) - # build a right-half circle - if fs=='bottom': rotate = 270. - elif fs=='top': rotate = 90. - elif fs=='left': rotate = 180. - else: rotate = 0. - - righthalf = Path.unit_circle_righthalf() - transform = transform.rotate_deg(rotate) - renderer.draw_markers(gc, righthalf, transform, - path, path_trans, rgbFace) - transform = transform.rotate_deg(180.) - renderer.draw_markers(gc, righthalf, transform, - path, path_trans, rgbFace_alt) - - - _draw_pixel_transform = Affine2D().translate(-0.5, -0.5) - def _draw_pixel(self, renderer, gc, path, path_trans): - gc.set_snap(False) - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - # There is no visible difference, so always paint it 'full' - renderer.draw_markers(gc, Path.unit_rectangle(), - self._draw_pixel_transform, - path, path_trans, rgbFace) - - - def _draw_circle(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) > 3.0) - w = renderer.points_to_pixels(self._markersize) * 0.5 - transform = Affine2D().scale(w, w) - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - if fs=='full': - renderer.draw_markers(gc, Path.unit_circle(), transform, - path, path_trans, rgbFace) - else: - rgbFace_alt = self._get_rgb_face(alt=True) - # build a right-half circle - if fs=='bottom': rotate = 270. - elif fs=='top': rotate = 90. - elif fs=='left': rotate = 180. - else: rotate = 0. - - righthalf = Path.unit_circle_righthalf() - transform = transform.rotate_deg(rotate) - renderer.draw_markers(gc, righthalf, transform, - path, path_trans, rgbFace) - transform = transform.rotate_deg(180.) - renderer.draw_markers(gc, righthalf, transform, - path, path_trans, rgbFace_alt) - - - _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - # Going down halfway looks to small. Golden ratio is too far. - _triangle_path_u = Path([[0.0, 1.0], [-3/5., -1/5.], [3/5., -1/5.], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - _triangle_path_d = Path([[-3/5., -1/5.], [3/5., -1/5.], [1.0, -1.0], [-1.0, -1.0], [-3/5., -1/5.]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - _triangle_path_l = Path([[0.0, 1.0], [0.0, -1.0], [-1.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - _triangle_path_r = Path([[0.0, 1.0], [0.0, -1.0], [1.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - def _draw_triangle(self, renderer, gc, path, path_trans, direction): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - assert direction in ['up', 'down', 'left', 'right'] - if direction == 'up': - x,y = offset, offset - rot = 0.0 - skip = 0 - elif direction == 'down': - x,y = offset, offset - rot = 180.0 - skip = 2 - elif direction == 'left': - x,y = offset, offset - rot = 90.0 - skip = 3 - else: - x,y = offset, offset - rot = 270.0 - skip = 1 - transform = Affine2D().scale(x,y).rotate_deg(rot) - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - - if fs=='full': - renderer.draw_markers(gc, self._triangle_path, transform, - path, path_trans, rgbFace) - else: - rgbFace_alt = self._get_rgb_face(alt=True) - - mpaths = [self._triangle_path_u, - self._triangle_path_l, - self._triangle_path_d, - self._triangle_path_r] - - if fs=='top': - mpath = mpaths[(0+skip) % 4] - mpath_alt = mpaths[(2+skip) % 4] - elif fs=='bottom': - mpath = mpaths[(2+skip) % 4] - mpath_alt = mpaths[(0+skip) % 4] - elif fs=='left': - mpath = mpaths[(1+skip) % 4] - mpath_alt = mpaths[(3+skip) % 4] - else: - mpath = mpaths[(3+skip) % 4] - mpath_alt = mpaths[(1+skip) % 4] - - renderer.draw_markers(gc, mpath, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, mpath_alt, transform, - path, path_trans, rgbFace_alt) - - - def _draw_triangle_up(self, renderer, gc, path, path_trans): - self._draw_triangle(renderer, gc, path, path_trans, 'up') - - - def _draw_triangle_down(self, renderer, gc, path, path_trans): - self._draw_triangle(renderer, gc, path, path_trans, 'down') - - - def _draw_triangle_left(self, renderer, gc, path, path_trans): - self._draw_triangle(renderer, gc, path, path_trans, 'left') - - - def _draw_triangle_right(self, renderer, gc, path, path_trans): - self._draw_triangle(renderer, gc, path, path_trans, 'right') - - - def _draw_square(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 2.0) - side = renderer.points_to_pixels(self._markersize) - transform = Affine2D().translate(-0.5, -0.5).scale(side) - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - if fs=='full': - renderer.draw_markers(gc, Path.unit_rectangle(), transform, - path, path_trans, rgbFace) - else: - rgbFace_alt = self._get_rgb_face(alt=True) - # build a bottom filled square out of two rectangles, one - # filled. Use the rotation to support left, right, bottom - # or top - if fs=='bottom': rotate = 0. - elif fs=='top': rotate = 180. - elif fs=='left': rotate = 270. - else: rotate = 90. - - bottom = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 0.5], [0.0, 0.5], [0.0, 0.0]]) - top = Path([[0.0, 0.5], [1.0, 0.5], [1.0, 1.0], [0.0, 1.0], [0.0, 0.5]]) - transform = transform.rotate_deg(rotate) - renderer.draw_markers(gc, bottom, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, top, transform, - path, path_trans, rgbFace_alt) - - - def _draw_diamond(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - side = renderer.points_to_pixels(self._markersize) - transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45).scale(side) - - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - if fs=='full': - renderer.draw_markers(gc, Path.unit_rectangle(), transform, - path, path_trans, rgbFace) - else: - right = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]]) - left = Path([[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [0.0, 0.0]]) - - if fs=='bottom': rotate = 270. - elif fs=='top': rotate = 90. - elif fs=='left': rotate = 180. - else: rotate = 0. - - transform = transform.rotate_deg(rotate) - rgbFace_alt = self._get_rgb_face(alt=True) - - renderer.draw_markers(gc, right, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, left, transform, - path, path_trans, rgbFace_alt) - - - def _draw_thin_diamond(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = renderer.points_to_pixels(self._markersize) - transform = Affine2D().translate(-0.5, -0.5) \ - .rotate_deg(45) - - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - if fs=='full': - transform = transform.scale(offset * 0.6, offset) - renderer.draw_markers(gc, Path.unit_rectangle(), transform, - path, path_trans, rgbFace) - else: - right = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]]) - left = Path([[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [0.0, 0.0]]) - - if fs=='bottom': rotate = 270. - elif fs=='top': rotate = 90. - elif fs=='left': rotate = 180. - else: rotate = 0. - - # scale after rotation - transform = transform.rotate_deg(rotate).scale(offset * 0.6, offset) - rgbFace_alt = self._get_rgb_face(alt=True) - - renderer.draw_markers(gc, right, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, left, transform, - path, path_trans, rgbFace_alt) - - - def _draw_pentagon(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5 * renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - - polypath = Path.unit_regular_polygon(5) - - if fs == 'full': - renderer.draw_markers(gc, polypath, transform, - path, path_trans, rgbFace) - else: - verts = polypath.vertices - - y = (1+np.sqrt(5))/4. - top = Path([verts[0], verts[1], verts[4], verts[0]]) - bottom = Path([verts[1], verts[2], verts[3], verts[4], verts[1]]) - left = Path([verts[0], verts[1], verts[2], [0,-y], verts[0]]) - right = Path([verts[0], verts[4], verts[3], [0,-y], verts[0]]) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - - rgbFace_alt = self._get_rgb_face(alt=True) - renderer.draw_markers(gc, mpath, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, mpath_alt, transform, - path, path_trans, rgbFace_alt) - - - def _draw_star(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5 * renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - - polypath = Path.unit_regular_star(5, innerCircle=0.381966) - - if fs == 'full': - renderer.draw_markers(gc, polypath, transform, - path, path_trans, rgbFace) - else: - verts = polypath.vertices - - top = Path(np.vstack((verts[0:4,:], verts[7:10,:], verts[0]))) - bottom = Path(np.vstack((verts[3:8,:], verts[3]))) - left = Path(np.vstack((verts[0:6,:], verts[0]))) - right = Path(np.vstack((verts[0], verts[5:10,:], verts[0]))) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - - rgbFace_alt = self._get_rgb_face(alt=True) - renderer.draw_markers(gc, mpath, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, mpath_alt, transform, - path, path_trans, rgbFace_alt) - - - def _draw_hexagon1(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5 * renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - - polypath = Path.unit_regular_polygon(6) - - if fs == 'full': - renderer.draw_markers(gc, polypath, transform, - path, path_trans, rgbFace) - else: - verts = polypath.vertices - - # not drawing inside lines - x = abs(np.cos(5*np.pi/6.)) - top = Path(np.vstack(([-x,0],verts[(1,0,5),:],[x,0]))) - bottom = Path(np.vstack(([-x,0],verts[2:5,:],[x,0]))) - left = Path(verts[(0,1,2,3),:]) - right = Path(verts[(0,5,4,3),:]) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - - rgbFace_alt = self._get_rgb_face(alt=True) - renderer.draw_markers(gc, mpath, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, mpath_alt, transform, - path, path_trans, rgbFace_alt) - - - def _draw_hexagon2(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5 * renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(30) - - rgbFace = self._get_rgb_face() - fs = self.get_fillstyle() - - polypath = Path.unit_regular_polygon(6) - - if fs == 'full': - renderer.draw_markers(gc, polypath, transform, - path, path_trans, rgbFace) - else: - verts = polypath.vertices - - # not drawing inside lines - x, y = np.sqrt(3)/4, 3/4. - top = Path(verts[(1,0,5,4,1),:]) - bottom = Path(verts[(1,2,3,4),:]) - left = Path(np.vstack(([x,y],verts[(0,1,2),:],[-x,-y],[x,y]))) - right = Path(np.vstack(([x,y],verts[(5,4,3),:],[-x,-y]))) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - - rgbFace_alt = self._get_rgb_face(alt=True) - renderer.draw_markers(gc, mpath, transform, - path, path_trans, rgbFace) - renderer.draw_markers(gc, mpath_alt, transform, - path, path_trans, rgbFace_alt) - - - _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) - def _draw_vline(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - renderer.draw_markers(gc, self._line_marker_path, transform, - path, path_trans) - - - def _draw_hline(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(90) - renderer.draw_markers(gc, self._line_marker_path, transform, - path, path_trans) - - - _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) - def _draw_tickleft(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) - offset = renderer.points_to_pixels(self._markersize) - marker_transform = Affine2D().scale(-offset, 1.0) - renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, - path, path_trans) - - - def _draw_tickright(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) - offset = renderer.points_to_pixels(self._markersize) - marker_transform = Affine2D().scale(offset, 1.0) - renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, - path, path_trans) - - - _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) - def _draw_tickup(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) - offset = renderer.points_to_pixels(self._markersize) - marker_transform = Affine2D().scale(1.0, offset) - renderer.draw_markers(gc, self._tickvert_path, marker_transform, - path, path_trans) - - - def _draw_tickdown(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) - offset = renderer.points_to_pixels(self._markersize) - marker_transform = Affine2D().scale(1.0, -offset) - renderer.draw_markers(gc, self._tickvert_path, marker_transform, - path, path_trans) - - - _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], - [0.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, - Path.MOVETO, Path.LINETO]) - def _draw_plus(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - renderer.draw_markers(gc, self._plus_path, transform, - path, path_trans) - - - _tri_path = Path([[0.0, 0.0], [0.0, -1.0], - [0.0, 0.0], [0.8, 0.5], - [0.0, 0.0], [-0.8, 0.5]], - [Path.MOVETO, Path.LINETO, - Path.MOVETO, Path.LINETO, - Path.MOVETO, Path.LINETO]) - def _draw_tri_down(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - renderer.draw_markers(gc, self._tri_path, transform, - path, path_trans) - - - def _draw_tri_up(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(180) - renderer.draw_markers(gc, self._tri_path, transform, - path, path_trans) - - - def _draw_tri_left(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(90) - renderer.draw_markers(gc, self._tri_path, transform, - path, path_trans) - - - def _draw_tri_right(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(270) - renderer.draw_markers(gc, self._tri_path, transform, - path, path_trans) - - - _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) - def _draw_caretdown(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - renderer.draw_markers(gc, self._caret_path, transform, - path, path_trans) - - - def _draw_caretup(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(180) - renderer.draw_markers(gc, self._caret_path, transform, - path, path_trans) - - - def _draw_caretleft(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(270) - renderer.draw_markers(gc, self._caret_path, transform, - path, path_trans) - - - def _draw_caretright(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset).rotate_deg(90) - renderer.draw_markers(gc, self._caret_path, transform, - path, path_trans) - - - _x_path = Path([[-1.0, -1.0], [1.0, 1.0], - [-1.0, 1.0], [1.0, -1.0]], - [Path.MOVETO, Path.LINETO, - Path.MOVETO, Path.LINETO]) - def _draw_x(self, renderer, gc, path, path_trans): - gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) - offset = 0.5*renderer.points_to_pixels(self._markersize) - transform = Affine2D().scale(offset) - renderer.draw_markers(gc, self._x_path, transform, - path, path_trans) - - def update_from(self, other): 'copy properties from other to self' Artist.update_from(self, other) @@ -1550,7 +903,6 @@ def update_from(self, other): self._markerfacecoloralt = other._markerfacecoloralt self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth - self._fillstyle = other._fillstyle self._dashSeq = other._dashSeq self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle @@ -1558,8 +910,8 @@ def update_from(self, other): self._solidjoinstyle = other._solidjoinstyle self._linestyle = other._linestyle - self._marker = other._marker - self._markerFunc = other._markerFunc + self._marker = MarkerStyle(other._marker.get_marker(), + other._marker.get_fillstyle()) self._drawstyle = other._drawstyle @@ -1815,9 +1167,9 @@ def onpick(self, event): self.process_selected(ind, xdata[ind], ydata[ind]) lineStyles = Line2D._lineStyles -lineMarkers = Line2D._markers +lineMarkers = MarkerStyle.markers drawStyles = Line2D.drawStyles -fillStyles = Line2D.fillStyles +fillStyles = MarkerStyle.fillstyles docstring.interpd.update(Line2D = artist.kwdoc(Line2D)) diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py new file mode 100644 index 000000000000..aa3fa5a7ba05 --- /dev/null +++ b/lib/matplotlib/markers.py @@ -0,0 +1,499 @@ +""" +This module contains functions to handle markers. Used by both the +marker functionality of `~matplotlib.axes.Axes.plot` and +`~matplotlib.axes.Axes.scatter`. +""" + +import numpy as np + +from cbook import is_math_text +from path import Path +from transforms import IdentityTransform, Affine2D + +# special-purpose marker identifiers: +(TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, + CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) + +# TODO: Cache the marker path within the object + +class MarkerStyle: + style_table = """ +======================== ===================================================== +marker description +======================== ===================================================== +%s +``'$...$'`` render the string using mathtext +(numsides, style, angle) where style is 1: star, 2: asterisk, 3: circle +(verts, 0) where verts is a list of (x, y) pairs in range (0, 1) +======================== ===================================================== +""" + + # TODO: Automatically generate this + accepts = """ACCEPTS: [ %s | ``'$...$'`` | tuple ]""" + + markers = { + '.' : 'point', + ',' : 'pixel', + 'o' : 'circle', + 'v' : 'triangle_down', + '^' : 'triangle_up', + '<' : 'triangle_left', + '>' : 'triangle_right', + '1' : 'tri_down', + '2' : 'tri_up', + '3' : 'tri_left', + '4' : 'tri_right', + 's' : 'square', + 'p' : 'pentagon', + '*' : 'star', + 'h' : 'hexagon1', + 'H' : 'hexagon2', + '+' : 'plus', + 'x' : 'x', + 'D' : 'diamond', + 'd' : 'thin_diamond', + '|' : 'vline', + '_' : 'hline', + TICKLEFT : 'tickleft', + TICKRIGHT : 'tickright', + TICKUP : 'tickup', + TICKDOWN : 'tickdown', + CARETLEFT : 'caretleft', + CARETRIGHT : 'caretright', + CARETUP : 'caretup', + CARETDOWN : 'caretdown', + None : 'nothing', + ' ' : 'nothing', + '' : 'nothing' + } + + filled_markers = ('o', '^', 'v', '<', '>', + 's', 'd', 'D', 'h', 'H', 'p', '*') + + fillstyles = ('full', 'left' , 'right' , 'bottom' , 'top') + + # TODO: Is this ever used as a non-constant? + _point_size_reduction = 0.5 + + def __init__(self, marker=None, fillstyle='full'): + self._fillstyle = fillstyle + self.set_marker(marker) + self.set_fillstyle(fillstyle) + + def _recache(self): + (self._path, self._transform, + self._alt_path, self._alt_transform, + self._snap_threshold) = self._marker_function() + + def __nonzero__(self): + return len(self._path.vertices) + + def is_filled(self): + return (self._marker in self.filled_markers + or is_math_text(self._marker)) + + def get_fillstyle(self): + return self._fillstyle + + def set_fillstyle(self, fillstyle): + # TODO: Raise exception for markers where fillstyle doesn't make sense + assert fillstyle in self.fillstyles + self._fillstyle = fillstyle + self._recache() + + def get_marker(self): + return self._marker + + def set_marker(self, marker): + if marker in self.markers: + self._marker = marker + self._marker_function = getattr( + self, '_get_' + self.markers[marker]) + elif is_math_text(marker): + self._marker = marker + self._marker_function = self._get_mathtext_path + else: + raise ValueError('Unrecognized marker style %s' % marker) + + self._recache() + + def get_path(self): + return self._path + + def get_transform(self): + return self._transform.frozen() + + def get_alt_path(self): + return self._alt_path + + def get_alt_transform(self): + return self._alt_transform.frozen() + + def get_snap_threshold(self): + return self._snap_threshold + + def _get_nothing(self): + return Path(np.empty((0,2))), IdentityTransform(), None, None, False + + def _get_mathtext_path(self): + """ + Draws mathtext markers '$...$' using TextPath object. + + Submitted by tcb + """ + from matplotlib.patches import PathPatch + from matplotlib.text import TextPath + + # again, the properties could be initialised just once outside + # this function + # Font size is irrelevant here, it will be rescaled based on + # the drawn size later + props = FontProperties(size=1.0) + text = TextPath(xy=(0,0), s=self.get_marker(), fontproperties=props, + usetex=rcParams['text.usetex']) + if len(text.vertices) == 0: + return text, IdentityTransform(), False + + xmin, ymin = text.vertices.min(axis=0) + xmax, ymax = text.vertices.max(axis=0) + width = xmax - xmin + height = ymax - ymin + max_dim = max(width, height) + path_trans = Affine2D() \ + .translate(-xmin + 0.5 * -width, -ymin + 0.5 * -height) \ + .scale(1.0 / max_dim) + + return text, path_trans, None, None, False + + def _get_circle(self, reduction = 1.0): + transform = Affine2D().scale(0.5 * reduction) + fs = self.get_fillstyle() + if fs=='full': + return Path.unit_circle(), transform, None, None, 3.0 + else: + # build a right-half circle + if fs=='bottom': rotate = 270. + elif fs=='top': rotate = 90. + elif fs=='left': rotate = 180. + else: rotate = 0. + + half = Path.unit_circle_righthalf() + transform = transform.rotate_deg(rotate) + alt_transform = transform.rotate_deg(180.) + return half, transform, half, alt_transform, 3.0 + + def _get_pixel(self): + return Path.unit_rectangle(), Affine2D().translate(-0.5, 0.5), None, None, False + + def _get_point(self): + return self._get_circle(reduction = self._point_size_reduction) + + _triangle_path = Path( + [[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + # Going down halfway looks to small. Golden ratio is too far. + _triangle_path_u = Path( + [[0.0, 1.0], [-3/5., -1/5.], [3/5., -1/5.], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + _triangle_path_d = Path( + [[-3/5., -1/5.], [3/5., -1/5.], [1.0, -1.0], [-1.0, -1.0], [-3/5., -1/5.]], + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + _triangle_path_l = Path( + [[0.0, 1.0], [0.0, -1.0], [-1.0, -1.0], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + _triangle_path_r = Path( + [[0.0, 1.0], [0.0, -1.0], [1.0, -1.0], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + def _get_triangle(self, rot, skip): + direction_map = { + 'up': (0.0, 0), + 'down': (180.0, 2), + 'left': (90.0, 3), + 'right': (270.0, 1) + } + rot, skip = direction_map[direction] + transform = Affine2D().scale(0.5, 0.5).rotate_deg(rot) + fs = self.get_fillstyle() + + if fs=='full': + return self._triangle_path, transform, None, None, 5.0 + else: + rgbFace_alt = self._get_rgb_face(alt=True) + + mpaths = [self._triangle_path_u, + self._triangle_path_l, + self._triangle_path_d, + self._triangle_path_r] + + if fs=='top': + mpath = mpaths[(0+skip) % 4] + mpath_alt = mpaths[(2+skip) % 4] + elif fs=='bottom': + mpath = mpaths[(2+skip) % 4] + mpath_alt = mpaths[(0+skip) % 4] + elif fs=='left': + mpath = mpaths[(1+skip) % 4] + mpath_alt = mpaths[(3+skip) % 4] + else: + mpath = mpaths[(3+skip) % 4] + mpath_alt = mpaths[(1+skip) % 4] + + return mpath, transform, mpath_alt, transform, 5.0 + + def _get_triangle_up(self): + self._get_triangle(0.0, 0) + + def _get_triangle_down(self): + self._get_triangle(180.0, 2) + + def _get_triangle_left(self): + self._get_triangle(90.0, 3) + + def _get_triangle_right(self): + self._get_triangle(270.0, 1) + + def _get_square(self): + transform = Affine2D().translate(-0.5, -0.5) + fs = self.get_fillstyle() + if fs=='full': + return Path.unit_rectangle(), transform, None, None, 2.0 + else: + # build a bottom filled square out of two rectangles, one + # filled. Use the rotation to support left, right, bottom + # or top + if fs=='bottom': rotate = 0. + elif fs=='top': rotate = 180. + elif fs=='left': rotate = 270. + else: rotate = 90. + + bottom = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 0.5], [0.0, 0.5], [0.0, 0.0]]) + top = Path([[0.0, 0.5], [1.0, 0.5], [1.0, 1.0], [0.0, 1.0], [0.0, 0.5]]) + transform = transform.rotate_deg(rotate) + return bottom, transform, top, transform, 2.0 + + def _get_diamond(self): + transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45) + fs = self.get_fillstyle() + if fs=='full': + return Path.unit_rectangle(), transform, None, None, 5.0 + else: + right = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]]) + left = Path([[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [0.0, 0.0]]) + + if fs=='bottom': rotate = 270. + elif fs=='top': rotate = 90. + elif fs=='left': rotate = 180. + else: rotate = 0. + + transform = transform.rotate_deg(rotate) + + return right, transform, left, transform, 5.0 + + def _get_thin_diamond(self): + right, transform, left, _, snap = self._get_diamond() + transform = transform.scale(0.6, 1.0) + return right, transform, left, transform, 3.0 + + def _get_pentagon(self): + transform = Affine2D().scale(0.5) + polypath = Path.unit_regular_polygon(5) + + fs = self.get_fillstyle() + + if fs == 'full': + return polypath, tranform, None, None, 5.0 + else: + verts = polypath.vertices + + y = (1+np.sqrt(5))/4. + top = Path([verts[0], verts[1], verts[4], verts[0]]) + bottom = Path([verts[1], verts[2], verts[3], verts[4], verts[1]]) + left = Path([verts[0], verts[1], verts[2], [0,-y], verts[0]]) + right = Path([verts[0], verts[4], verts[3], [0,-y], verts[0]]) + + if fs == 'top': + mpath, mpath_alt = top, bottom + elif fs == 'bottom': + mpath, mpath_alt = bottom, top + elif fs == 'left': + mpath, mpath_alt = left, right + else: + mpath, mpath_alt = right, left + + return mpath, transform, mpath_alt, transform, 5.0 + + def _get_star(self): + transform = Affine2D().scale(0.5) + fs = self.get_fillstyle() + + polypath = Path.unit_regular_star(5, innerCircle=0.381966) + + if fs == 'full': + return polypath, transform, None, None, 5.0 + else: + verts = polypath.vertices + + top = Path(np.vstack((verts[0:4,:], verts[7:10,:], verts[0]))) + bottom = Path(np.vstack((verts[3:8,:], verts[3]))) + left = Path(np.vstack((verts[0:6,:], verts[0]))) + right = Path(np.vstack((verts[0], verts[5:10,:], verts[0]))) + + if fs == 'top': + mpath, mpath_alt = top, bottom + elif fs == 'bottom': + mpath, mpath_alt = bottom, top + elif fs == 'left': + mpath, mpath_alt = left, right + else: + mpath, mpath_alt = right, left + + return mpath, transform, mpath_alt, transform, 5.0 + + def _get_hexagon1(self): + transform = Affine2D().scale(0.5) + fs = self.get_fillstyle() + + polypath = Path.unit_regular_polygon(6) + + if fs == 'full': + return polypath, transform, None, None, 5.0 + else: + verts = polypath.vertices + + # not drawing inside lines + x = np.abs(np.cos(5*np.pi/6.)) + top = Path(np.vstack(([-x,0],verts[(1,0,5),:],[x,0]))) + bottom = Path(np.vstack(([-x,0],verts[2:5,:],[x,0]))) + left = Path(verts[(0,1,2,3),:]) + right = Path(verts[(0,5,4,3),:]) + + if fs == 'top': + mpath, mpath_alt = top, bottom + elif fs == 'bottom': + mpath, mpath_alt = bottom, top + elif fs == 'left': + mpath, mpath_alt = left, right + else: + mpath, mpath_alt = right, left + + return mpath, transform, mpath_alt, transform, 5.0 + + def _get_hexagon2(self): + transform = Affine2D().scale(0.5).rotate_deg(30) + fs = self.get_fillstyle() + + polypath = Path.unit_regular_polygon(6) + + if fs == 'full': + return polypath, transform, None, None, 5.0 + else: + verts = polypath.vertices + + # not drawing inside lines + x, y = np.sqrt(3)/4, 3/4. + top = Path(verts[(1,0,5,4,1),:]) + bottom = Path(verts[(1,2,3,4),:]) + left = Path(np.vstack(([x,y],verts[(0,1,2),:],[-x,-y],[x,y]))) + right = Path(np.vstack(([x,y],verts[(5,4,3),:],[-x,-y]))) + + if fs == 'top': + mpath, mpath_alt = top, bottom + elif fs == 'bottom': + mpath, mpath_alt = bottom, top + elif fs == 'left': + mpath, mpath_alt = left, right + else: + mpath, mpath_alt = right, left + + return mpath, transform, mpath_alt, transform, 5.0 + + _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) + def _get_vline(self): + transform = Affine2D().scale(0.5) + return self._line_marker_path, transform, None, None, 1.0 + + def _get_hline(self): + transform = Affine2D().scale(0.5).rotate_deg(90) + return self._line_marker_path, transform, None, None, 1.0 + + _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) + def _get_tickleft(self): + transform = Affine2D().scale(-1.0, 1.0) + return self._tickhoriz_path, transform, None, None, 1.0 + + def _get_tickright(self): + transform = Affine2D().scale(1.0, 1.0) + return self._tickhoriz_path, transform, None, None, 1.0 + + _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) + def _get_tickup(self): + transform = Affine2D().scale(1.0, 1.0) + return self._tickvert_path, transform, None, None, 1.0 + + def _get_tickdown(self): + transform = Affine2D().scale(1.0, -1.0) + return self._tickvert_path, transform, None, None, 1.0 + + _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], + [0.0, -1.0], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) + def _get_plus(self): + transform = Affine2D().scale(0.5) + return self._plus_path, transform, None, None, 1.0 + + _tri_path = Path([[0.0, 0.0], [0.0, -1.0], + [0.0, 0.0], [0.8, 0.5], + [0.0, 0.0], [-0.8, 0.5]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) + def _draw_tri_down(self): + transform = Affine2D().scale(0.5) + return self._tri_path, transform, None, None, 5.0 + + def _draw_tri_up(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5).rotate_deg(90) + return self._tri_path, transform, None, None, 5.0 + + def _draw_tri_left(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5).rotate_deg(270) + return self._tri_path, transform, None, None, 5.0 + + def _draw_tri_right(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5).rotate_deg(180) + + _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) + def _draw_caretdown(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5) + return self._caret_path, transform, None, None, 3.0 + + def _draw_caretup(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5).rotate_deg(180) + return self._caret_path, transform, None, None, 3.0 + + def _draw_caretleft(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5).rotate_deg(270) + return self._caret_path, transform, None, None, 3.0 + + def _draw_caretright(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5).rotate_deg(90) + return self._caret_path, transform, None, None, 3.0 + + _x_path = Path([[-1.0, -1.0], [1.0, 1.0], + [-1.0, 1.0], [1.0, -1.0]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) + def _draw_x(self, renderer, gc, path, path_trans): + transform = Affine2D().scale(0.5) + return self._x_path, transform, None, None, 3.0 + +_styles = [(repr(x), y) for x, y in MarkerStyle.markers.items()] +_styles.sort() +MarkerStyle.style_table = ( + MarkerStyle.style_table % + '\n'.join(['``%7s`` %33s' % (x, y) for (x, y) in _styles])) + +MarkerStyle.accepts = ( + MarkerStyle.accepts % + ' | '.join(['``%s``' % x for (x, y) in _styles])) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery.pdf index 765a6fc41ce54d8c9f8ab24c4f1bbf996a08fe47..27dd193badb5dcdb158aa0b708e3a7d1c76abd1a 100644 GIT binary patch delta 3570 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 IoWqO$7wMNJJO6M}&8u`DX3LTD zTWVF3w75?Az%CZ`H&7>C2>WreYy!FQ(q(|24*FQ6%a!p$v{JU!A z1^&S<6+7e=^|H$bPD6|y_TD+!7?t2?(ts`F0lv~k0VnrR zp}gKZjx9IsUMU5?yP~?s;MwuzFolmq*p^5V0 zf{5S*rN=kvnMZ@yABw1sY6W^#=cEeHQ<)*42MvggIA*^wQvK-U!$Zjz%wA9jC` zbF^5#tY+8i>31q`x}R1orrTcJ5mM0)q;al1N!8k|C#6B=x7B70V0&*1y*D^kH1Rs{ zp_n-5iAkzit!=3a8m}E+rLh5s4X3<#fNdZZoqUyaq+T}a1uu5PYL#47oh>VO1Ts-1&azLV+n=}p z!B5-^4>qg-v36w#USq86gq}LBZ=@3T_`qosEfFlQ<3=ykK!m=hwIj>A`V#bNpoRV- zX1XrgHpMYJybso}{_Jw2jxe`jUui~+T|0Sy#-AKczZ46oy7?+>pW8JvdJlUcDV*3U zi-eaqu>1|(6Sm(LzgG4~e^RZ??!Nme1=+FO68B|=k!75K-Ed4$NLFcr`-b(v)0m064SY&8r-B>{HQY$#5a4G8c(TioP zlgMS%aTlQ3K+#w8UE{dZ&b~GowQxk}OpBL8iWf0B)3AJ2-Fut%GKaCl>nc>yy6HqY z9dD#PbhSe1WzDsV4=%3=DXnSt6xQzyzL!Glk2&RIN2`CYee|weHqnM1n?sY^`9YQb z&dOYG3tDIB(36HQPS&@s@716R14~eX2c%Ap-jEWYR+f~_ZFuUpxonqxBApp(r98Hr zJHAWjq8Zg@^z)_ZC|ndy9Egqmd@`482W(@VORAv@guZ!#0;Vz}IrhfS)$S)cz~Yq> z!Klq6Y-(8m-@eI_Ka3C;3AQxnxZmdXGRf0gkscI%zfK02tjD*P%5{gyM0o%d^~nRQ zz4c(lFNH`^2hZBuK>Q{4(U@dly+N7KmkS&c$L z;DRF<=u~GUce7*2beA#+6n<9DE+Xz<{RpeIPiuLT9Y{dfP# zDo-H1ZAgNJJq5Gm(%mRC${LJh$A0igVsM@yuyB(*EExitz2CT<#RG)JBuY6Ew9C>3 zHM1Eai>Lj_?H85491>+_cryvcDh6W#>%iE}6cPnJ1H$eCiP?b+^~~I1iswB*4j_+G z62((UC%?*yccbWBRcAOiU2@>t%kAOEa@=p9Yaz5Z>kTh^H)$PgxoCX77H_ zHyT-jzZwgvQ#xdmJn`MfqroQ`Rt%JwXf@uA4n4$wc{y43P99rX<43_c6i5Q5>VP#Vv zbDX}J-v>p?Q;tt@M&=lQD!kAWYVJ}{!;dQGL~4XYT7Fr)qS^!N zlL&q;s{^fXWX-C{MtmvBWRJ9sx#nK@E3CD#PgLk=+cuxs$<_!~8o`Ki1`o<;-+Gc3 z%%ChNnJu6GN^Q$}I$WLfb^3(%Sd+gtd*lnQF2!-x#>50dk=hnuVm`fy#``$kE)<`_ zaw5OC7<;|%!WW2&r&<{$_X(XInVnCK53T9&IMcc2nWgTQOqVnrS6o|YK+QpCpD})o z2*PHkX*@b%(z~n4ad*WGr?@A1;tN)(1ed!{G&lKu^UF9nwq}0N?3%4m{2~5avD9c+ zg5Issne#7Z!#{9*I?*i;Ejj(2SfQnRa~Yeh2pp(JH0^x+!M{0Y=UxT9Sp5s3BqYUsUdZ zxY$~Z^winpm}60Y_{iGqf!`UtVg#)uyOEfo9nobpG7 zdE?^QG6G$AdqN`C2a-9 PVHE-nF*4feY7hAjlYF^) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery.png index 1cb40c852e2460c3c956c704ac7551438a76fb55..f1269a1204159b962f5a90bc1762743955686fd7 100644 GIT binary patch literal 33511 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 z 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg index 71c7d45610dd..94543fc9ebde 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg @@ -16,7 +16,7 @@ L576 432 L576 0 L0 0 z -" style="fill:#ffffff;stroke:#ffffff;"/> +" style="fill:#ffffff;"/> @@ -41,7 +41,7 @@ C-2.6839 -1.55874 -3 -0.795609 -3 0 C-3 0.795609 -2.6839 1.55874 -2.12132 2.12132 C-1.55874 2.6839 -0.795609 3 0 3 z -" id="m1a9f33571b"/> +" id="mafc88db4ae"/> @@ -49,106 +49,106 @@ z - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -159,109 +159,109 @@ L2.54558 0 L2.44249e-16 -4.24264 L-2.54558 -8.88178e-16 z -" id="m485129bbfe"/> +" id="m016d603646"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -272,19 +272,19 @@ L3 3 L3 -3 L-3 -3 z -" id="m50b0a34c9f"/> +" id="mbfa5fcfaff"/> - - - - - - - - - - + + + + + + + + + + @@ -293,14 +293,14 @@ z M-3 0 L3 0 M0 3 -L0 -3" id="m68a135573f"/> +L0 -3" id="mba139cba6e"/> - - - - - + + + + + @@ -309,20 +309,20 @@ L0 -3" id="m68a135573f"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -358,20 +358,20 @@ Q19.5312 -74.2188 31.7812 -74.2188" id="BitstreamVeraSans-Roman-30"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -411,20 +411,20 @@ Q31.1094 -20.4531 19.1875 -8.29688" id="BitstreamVeraSans-Roman-32"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -460,20 +460,20 @@ z +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -518,20 +518,20 @@ Q48.4844 -72.75 52.5938 -71.2969" id="BitstreamVeraSans-Roman-36"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -584,20 +584,20 @@ Q18.3125 -60.0625 18.3125 -54.3906" id="BitstreamVeraSans-Roman-38"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -631,20 +631,20 @@ z +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -678,20 +678,20 @@ z +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -736,20 +736,20 @@ z +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -766,20 +766,20 @@ L-4 0" id="m91faa7d459"/> +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -796,20 +796,20 @@ L-4 0" id="m91faa7d459"/> +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -826,20 +826,20 @@ L-4 0" id="m91faa7d459"/> +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -883,7 +883,26 @@ L262.157 139.266 z " style="fill:#ffffff;stroke:#000000;"/> - + + + + + + + + + +" id="mafc88db4ae"/> - - + + @@ -1065,7 +1084,21 @@ Q52.2031 -43.7031 52.2031 -31.2031" id="BitstreamVeraSans-Roman-61"/> - + + + + + + + + + +" id="m016d603646"/> - - + + @@ -1157,7 +1190,21 @@ z - + + + + + + + + + +" id="mbfa5fcfaff"/> - - + + @@ -1220,18 +1267,30 @@ z - + + + + + + + + + +L0 -3" id="mba139cba6e"/> - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.pdf index 152014438026755adf05747de8e2fe28617e6551..e1c3819973bd57da16239eb868b1a0a73ab2384b 100644 GIT binary patch delta 3685 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 delta 3691 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.png index 12f1a821d039b210343ac573d23d2cbc3b465c68..2e9688d632ac669bb6820c842a69dc9d0711cc09 100644 GIT binary patch literal 49689 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≻dKu68SS!lH2j8c+l1K( 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 Q))@u=)FBj9pkxvJUvq#`?EnA( literal 49782 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 z

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 +" style="fill:#ffffff;"/> @@ -147,109 +147,109 @@ C-2.6839 -1.55874 -3 -0.795609 -3 0 C-3 0.795609 -2.6839 1.55874 -2.12132 2.12132 C-1.55874 2.6839 -0.795609 3 0 3 z -" id="m1a9f33571b"/> +" id="mafc88db4ae"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -361,109 +361,109 @@ L2.54558 0 L2.44249e-16 -4.24264 L-2.54558 -8.88178e-16 z -" id="m485129bbfe"/> +" id="m016d603646"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -575,19 +575,19 @@ L3 3 L3 -3 L-3 -3 z -" id="m50b0a34c9f"/> +" id="mbfa5fcfaff"/> - - - - - - - - - - + + + + + + + + + + @@ -697,14 +697,14 @@ L518.4 342.668" style="fill:none;stroke:#00bfbf;"/> M-3 0 L3 0 M0 3 -L0 -3" id="m68a135573f"/> +L0 -3" id="mba139cba6e"/> - - - - - + + + + + @@ -713,20 +713,20 @@ L0 -3" id="m68a135573f"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -762,20 +762,20 @@ Q19.5312 -74.2188 31.7812 -74.2188" id="BitstreamVeraSans-Roman-30"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -815,20 +815,20 @@ Q31.1094 -20.4531 19.1875 -8.29688" id="BitstreamVeraSans-Roman-32"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -864,20 +864,20 @@ z +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -922,20 +922,20 @@ Q48.4844 -72.75 52.5938 -71.2969" id="BitstreamVeraSans-Roman-36"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -988,20 +988,20 @@ Q18.3125 -60.0625 18.3125 -54.3906" id="BitstreamVeraSans-Roman-38"/> +L0 -4" id="ma54c094c92"/> - + +L0 4" id="m9416ebf055"/> - + @@ -1035,20 +1035,20 @@ z +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -1082,20 +1082,20 @@ z +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -1140,20 +1140,20 @@ z +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -1170,20 +1170,20 @@ L-4 0" id="m91faa7d459"/> +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -1200,20 +1200,20 @@ L-4 0" id="m91faa7d459"/> +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -1230,20 +1230,20 @@ L-4 0" id="m91faa7d459"/> +L4 0" id="m9fc5077edd"/> - + +L-4 0" id="m560f5ef9cf"/> - + @@ -1291,6 +1291,24 @@ z + + + + + + + @@ -1305,11 +1323,11 @@ C-2.6839 -1.55874 -3 -0.795609 -3 0 C-3 0.795609 -2.6839 1.55874 -2.12132 2.12132 C-1.55874 2.6839 -0.795609 3 0 3 z -" id="m1a9f33571b"/> +" id="mafc88db4ae"/> - - + + @@ -1477,6 +1495,19 @@ Q52.2031 -43.7031 52.2031 -31.2031" id="BitstreamVeraSans-Roman-61"/> + + + + + + + @@ -1486,11 +1517,11 @@ L2.54558 0 L2.44249e-16 -4.24264 L-2.54558 -8.88178e-16 z -" id="m485129bbfe"/> +" id="m016d603646"/> - - + + @@ -1573,6 +1604,19 @@ z + + + + + + + @@ -1582,11 +1626,11 @@ L3 3 L3 -3 L-3 -3 z -" id="m50b0a34c9f"/> +" id="mbfa5fcfaff"/> - - + + @@ -1640,6 +1684,17 @@ z + + + + + + + @@ -1647,11 +1702,11 @@ L292.397 125.471" style="fill:none;stroke:#00bfbf;"/> M-3 0 L3 0 M0 3 -L0 -3" id="m68a135573f"/> +L0 -3" id="mba139cba6e"/> - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_point.pdf b/lib/matplotlib/tests/baseline_images/test_axes/single_point.pdf index 454494789a286fad6d668c5525e10a0447384d08..3aed1e9a2534f8a25d879b2f8d0e58f59428c7ae 100644 GIT binary patch delta 2217 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_point.png b/lib/matplotlib/tests/baseline_images/test_axes/single_point.png index fe85f49765d19380be408016c88af6958b0b6873..162fdcde73da436bc743e65c392b5f5ea8ae54ab 100644 GIT binary patch literal 26381 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 A@Bjb+ literal 26316 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

gYbm+f%^9IPb zLT#ohbUNY~kDF@vQE%(qBZ9cxr*~3){F)@zkxdsJ>P|aw;6Qh6V$fQCS_C$x@rS2J zlB`ssPuE=IagV_k(0KMx$|<$kv6TZ5!uXx<*2T+~)t(fjM*s|(c2!0uHQ&CybSp3K zjvYIWJ2X2*1HCo2?*V=Tcx436Cy&6mjyLn4gg@=jhR@Yc4lRs~jNG|*uhQj(%l&!h zFIcc^>((QOt}V0k=G(DD5eXC3=SZEwy;{Sfl~BiQx}fR;|@Qb_>|%4H@z* zW^zE`=ZY7<&wKFj;SLLne$H0lp5bPf{w{ovyumF#Qcv^UCPhcU7EwIczG*G<+>OFK zB_)M`BxJPVQlat~kC|!EHTjqNAB)=vUwHeA*~e!GzzYQKIrm3j{-n8@x_XYcB=RXi zg2q)*U99ASTC#7j4`&NX(=)ib+$|*kuOCzN1BH!!feU5UtX^$|z>6>!u#870!7$V< zqq$kyWyGkjF*|VI#ha;VY3cgK%Mx{R)f+M`n22aiMKY5;X{6TgYszKU8HS>gmMiq) zsEVNa*?u1z_*3bB2DRCL6Z(CL3zl)C5kPeOxFx;qeM5s*a^B!gY#;RmO{-w_g%n2d zjaA!)&%Lrea?D5Z@aw6YcetM{S{21YH6t%ALXlgA5BCL$@#)i9c3)FNA~z3D^85EE zdXadVo86}-cJ9~_bF}~7mSd`_s=QQEnjs}fBEz664V7_Qy>cb6$M8`a2Sr$+#eFid zFH8TvKfjA&c6MkdD|sfNv5`&7=sD12RlMWi&lJb~fGh|pD6o^29BO;)C)GyRu3eim zm6?$eEa_msX`yFr_jt#Q*0p5}KjGuP1Icj#5eFn}JJ(DN1`M&x7f_x%1K7SVDM3h8 z3~x@-kz@|k@8?>krlBDg!yIqPDXL|2Q7ULXb$)!tXEz;NIL+Emd7Ko-$&YGIu9vTwcmy!XS(OC-2I3g^X`;Mz2Z5PkoVzp-~OE%Jli}-i$;qJ zKjxF;y+Ot`tH(YUFt|TXoQF?9;Pmgm|Lz;nU{RnW)@17^Gts#va~d%)7D;l;(c4+v zC+B$@=udyw>&|GGwtn*{!s7pHIFz|(DI-wiBmpWw zv1*!{F<|g^A!B{`@L{5^+})rnaLx-8!q*@T0KJB;UL&F`?cA6g6LXJKc3J_r_JIV5 zmTHxsD8j$`pU3+@h?MPFy1{GGB|y@)Gwk_u z;jP=YnSA^7(l-M6GBP5| zo}9^zjh=(xytGP~5fyS+1O+ufdSO?GkpMno6}(P_ z6zD4?5Ow}kpc~2w)I^>PSa9`^dW3gjBW+Y@W49I|E@}TUI**jM|B~GC$3W+~^5@D! zq-kje-sF_7S`{7A|;K_AMg5a+ZQSTWI3T%OpREk#nq7zFIXH!nn=+Hs%*~UwDTE|Q_GKLcXyfQsIDNYI z*}1~!7faS+6?Y&FlhWAEF5R>gyn!7nF|!*aW_D#|<#U8*>Cr};o7b;b`15NeF)Q%_ zo(APO%XlA1wozBE{Ny&pX4dD}#mmfmx7oDcQclRQEbr1xJ0pnQ9%Rw|W}TiYsL1@W zFH89K^0hb1~Ge|dSK>DRaSXc?Ct#l^*S_bO1SN+|dY7=dkZ-kT)V!NpZd_UE<6 zy(uncX%tL6XlO`uW_L#tWIi^~Dgo|kOA=|I7>P^mA~-i53zWmI)oSV<7#JXw*fOsD zmUYtyE-$Fb(&d$r(XFei!?$heQ)R5f1n8ds0dzb5l69pa2nEv(%N~C~>PX6&K_;W6 zoWJTk-1!7~Oz+)~8b16;%lwkhmcmAlLqkJ(QHN;HnKMV^PNpfd%q~x$Okblx)~;I> zwX9iVR>}bzf=_7SYc~>7!j7rqAYyb03^pp)3u$#GbV}oyw7TwT`~5yT@-wJ=*hskD zK$FahCx-+jTmEa%mv)JA18)|L52x^mzn1wuUT}e^e^o^8tXsG4q%Y!hx9e??+2D-y ztY-e0zeE_t5(6v{@GwVUKfbYg)vBtn6x?c-jLGEuZ-5#gj~WgOnQX$vyFR9bV@Ek0 zkw#fkpQ3-v+xhhAJG?t3By!4hd3bo(ogWTiebYxK$H%)e8q96tqY*{wpBo2?ngzC( zKC(GtLl{8X7N4A--Ckc`v5Swd3j0bYeaSk3&Tt1PC(k?^Gd`_*9=mLGGP+Qcuv9AsG9}OvFey^d;c^ znSg58wPQyGe)4`$P<&mQA#?r4wQJkePo6%lj-WzV&fcb6jqL1fP9cNa1aF}%%qapJ ztL7s+oi*JuGwDG%ID(M#?{JBqf9Fg%oc5?U`SV#OW8>pH`T6CMThv`$^JW=(5-DSp z!W)Y?y*^JgE(4J*VT@`M7`W1N&OBZ!cn0Tw`lz;te*}tGau`qz$qHY5f1lF_cc$K& zb{x+^Q8@cB%2<@m8+Z`)CkZ7hR{ZMWF~ip_BCi4l6j9`X^GMH59-h#nkNo~4MD8XK z*^XsjL-#rt1E$=2|3+N&g^**l$Yyf+z_tInt+yYYESHg<4}l`4C zM_T(KxdC0x`KX_0&N zi#l&?52+xvx8_Nbc4%DKU*qHBWKRPx4dalSVv9|DA1b%|^kNQ3r=irTATf*DAdCFi zb$YH!j~+cDM8k7%n{E?b(X{7AN{Q0g6qPCp(vdEG+0iKhq}qDEAGpqaX0nBa%6FpI z!h;n@*d&DVY8+_1Z8Zyz6DMxYoi|SeT^kLvo{uTrHSqz>P94EC7ZSQ-Vs?1*$mT26 z;$oEN7k<#6HR+}rP0p-DbN1MnBZ0~bmvLoXnh85_*+g4#C7^Ck&n0}jJ~7{E$bb;e zx7G=oKPIP?!v7dtFIrD%_L0sEK&#zIh`7yBka|XzGdM>gIC#=C--o(CgcqluBD>2- zgf^`6jBDAk%SBirs_&m*YO5p88G0>Wq-ras(X)8ZWNLsMF{5rYDuU62B?O=S#bCI^`F5~CmhfZ4$WNwnwZqd`*pRocT*RGFCE(Z z#~*)u?d@#}o9+np&_&KsK6B=g%=DN(wG!0v*4b7H*iZL~s?geT?Imk>E1o)a>X1Jo zx+g0lLyywmkg0$QOkOy=_6a@>)R9SJmX${Jsx@mO2~;C|!ExWG;o+lbyi&Nd*n4K1nCrJpWE7^YkvlakAm%W@vMjKlXAnR_tx{}fp1=%T8q<)_~ zI(;iuE7QCNWN1_Vu=yW{F44$D8@uY{jeL;Q(4_2?;% z4kJW5x9B4}z?n3%`st?8AHt8BqJ#RL!Kgt)PZb}8J^w*O0JOpnKJ^xJ-n@BW;a#WJ zEx`u}AL1Y3*VHI1FIO-&HYTjKtHI>saF???CR}F*a4Cv{{(mJxI;lD2#CiW;5+MI+d>LMwg3LzHC{ou`RCz44 zII7WyZo`JxESZgHOMN8g4FcSmRD>O%<=Q7&+t`Spk%*FYQ(R1pk)j9QHE?Sb&d`o6 zTMj`xzzG(T)RMQ|*fknx;`5LMT-7o?B9^F~t-M@jENpsuv_Nbm_3ZD})zyEeJ@-G3 zq4yd-qNPQ8_<`WL@~1|$dRq$gjvP5Mf!02Xa%;N(b=Gx{p997IvL#$Wb5f;@PxX5w z6UdQSFqIfD3JmGZC9X^;WdvFJ6uJwfkOjxDoepRoheob*N3esoNR_aNe$mo5uU~h9 zL$-Bs(ZE3_+|5z#HQ0<5){d$as)B+BdSL`}=a7z*-NdjlF!ZO?DJU!Atmwyq5kQlW zZ_jr0QHlEc`tnjCQa}^I%j5d(cha8% zIcqfB`Jq0;ENH=UZtV`|e5~by#3i-6`1xyq1OuHpW9Cg(xu%FQ*11&WrN}b;hU`#q zb_6x3_1yfUqxJb6MuT>kgL z5?W|07`2+o{(|Ih-z=Lf3poO`Nb1<#Zn^&g_zYk(QMM{A0a%?>w^pr1I!X%2Nhqt8 z!bAN0wopM-B&9Kni;qb=4=dW++b2#zCy>*d(ZEZ^Yw@2|545$lZLJbEb-Pnhq3FFq zsC{q=&YGNG_E4E*kn>{xz+?ZFp#B$u+}zP<-8B{@I$`c$$hHY;~vqaU?hEA*3-H3Z@VVkYqv{>I->X6_JfdCnR~2hUfBZ zkNGd4;a>~)G@5{jubg1B!1qSXnYZA$?;n>hv++8zr+Y{<~T_ zY=~Yry}c6$oPJ~1{RiY1yH_?EX({nc+Rw{>^~D?|1) z$U+I1k%T__s4mm)M9jOJbaDHhhp3K84;;)N^ai`oZ$q7 zCXA5SIi}@mps6C5-g-Y5=YGpD$RJFoJd}(|GiitU=7><>szw$K-dZrdxZib^{hEsG(v)HNDiKEIkTBqqizegA$RA0HoU z69DuX8@#qC-ZZ4~b{~)L`c>%vEVH28CI> zLyMb+eovm$&?)f$Lg-2KFq1=_5Y+;~#I-{OW%GtLyxJmfz{_~OR~_~|D_{0BpGJ}} zN8uj)J2MziAY7|V+r&3w0J=8{(weTewu|;?E!@6&b03{fXP^olN-LMi)jest*Iz)# z#M#9q2u;qt*OqQLpJ7~8bo=&gVTBMWr@Ce!%^UA|llG-vjux>Qzrf_kfSe>vdDIdXAa0(}w@7k2l>`b(l| zc!BLGkCHknX;OUd_5$hW3KuX7`1%WG-1P+_Yf?-sfHsXL#>O7vCq=NaOuepM3&PVI zsH@kqHPvr@NtyF{m!8K|I=Q25+qUJHApAu!41`dlc9o1+)IWbGytMG~UVX3ljPq|6 zSM6D9^ZC_PbA1&R75TzFrF!4LtcxoAY*{ljI9Lh^!ck3mmVVpxe(0crWXE1EFLmjs z2T+uk$B(pQnS?qRL59<S&PK7ayw6@6OG``9p_U&) zr}W2Vp#8e+gc74jN0smVo9UkV^peNYE*VZ}6l(Cx%C;bLq;9ouGtHflRpocN` z-`X{6vTJx8Kg|)^v7S`IUAkd zhY(T4j-IO4_mMUrJ8d^Vzg_%H=P}uRg|A*|dkFCH3AwqtmO^M$YNicbj!TW}&9L>n zpZV6lyEzqGGV{HB<{`Ed-nWL>xO!PP-3fIa11h5-L67kzbH47wW4ljHJVJK()~R>C zrZ`;Spv7YRIJ7zO=5)4trZaHB=}?(O^o6xEJOH~ynukc^;YT$_^96Ud6WS<1U+Oy9 z>Ti{~c2DfpdwmF7l5SG7i(fY{%W7@K%`(uJ3b z&TlP_cl57^yt2GmNQq#DAmVI39&hZH@G&&!+mMnh->3ml3@X)ov*o45%yI|y9`7b| z4J-$%9&(G{+B!Oz6X$9}ZWhEc&-|N8CjHebG>6L{i-)h;ep)z27V^u=H{~0;nsPHq zp#z;d8i~5Z#(@shE!fyuPlFKm!J4X+b7FHWs{)?ivbM;4Z!4s zQ@Lu{jocr5N8ld8n*aFERjU>1oBsfqrm#_n78AHH3h2R`TbkxE z#nMZ*e#3v#riq6dC~gx4UJ*#~cD$DM66Rw(OVsJ$U3ik zhL8~*(J8dB)o?OI&b|7HPz&Cv{{E#<7P%z;J&sYjtsP1uJB#0kG!IP#N9*XHKR*ny zMQ%}|R_19ip3dNXA?EwEfI*KmDVt1#)Rtd6OA%CtzmJc?<@S$(!X5PSeBizACWn?9 z^bC`raS=5tORTBsd-=e1Mo=sx-)+QJy{CMX{9-bFB+#HdBoVRTTU>kZqJ)n@q=F0* zQ$V7)^sQI_9HV)^o*(Hq_ueip=J7~CT}dCQH|3OZ9TQ1-+SWSLqp|t7-wpzqn^tIc zbVywJhis-;j4X6LzP6)H4!Pb-I5^bMnHz2k&=WOk=09W89QvQu^`b_7{7N>>L9-nz zoA%NVSmpbVA2)`LXBa?RmDJCS6v$jC8YGWy5y!-|cIBBgokwDT4Qr4OIriBQT;I9x>L_Z66){L3iHYXAOE^9R;Cr_>te8zDLElOMX--n3GrV+y1sx(Rra3G+}TizQ}7b4-}q|x*8R&UtQHL@PW?!>6a zi~}%3!6K}3@sfyPSq}mm1yDT+&`R7DbLgx{v&5=3P;**j@!^6WF zAhj}6wkw3#<}!1T)@;h94V|5w9^s-%G$*I*I!F(OWT#tY8;iWIUVS7xJ>b)1f*`PO zYHErRI@M$7{rqX|n>ex>BDZecYRZRNkbFi|R8%0yL#FXn{(uLvlGtHFc+k@AXm&{? zM6_AEpKS-Z*3?aCLMNiGnbrpV+d4S|d!K~huqY4iex7@$kUfZ}-w zCW1Z7xuuM@@$x=|>bM>GttrHiXjx_)ATfU1`0U)}*{gz-vvyNlZ<2c6W2CRibYfy6 z5XZ7z%Yv@f+OY+Iq*5evwfa<#Yv@p6{}|WZoHOZS9^mW9r;-Kwj!nrBEcjme{hfmQ zd9sDTKKUnRX8-1?`3cIbeFWiQW8hyz_S*0LGt&@XJoeaIV1d6eK&sK1!Ur0dn3yD% zi+D`C3T@u}LS!T=$oz}g^?-A2)7nIYG(0%?n`d?5O}bTx@xb7qwYQCXifoi|W&;Ca z>zw@U1XYQKu6g32DQMCN-78J~^VFyOVLZyRl+X+ZF5=Nh+95zPRdfMBlbUYQg1i}q0m3~HN(ijE?ab6@36q(b;!k=_&)5G@Fughf_NH>V z$JilA7jsPb)DtSO<2kEkNqY@;6>uTl6;Cb$9LJ*ZOYrB>7)Ml7!e;ft;}a8csLqh* zRUj6GE+H9Zrf_!-StkD%t<8V5p|h$Kew1jqXjzs|c;D^0y@1_Umv#&T>RmjTSa2UGFy8oB6)9^giGlh+H5vPB$G~T<+v2^pyqJ z1v8TcIUOM`!>BCz_U;`>ZT;u1FIA3>8}6Fk0|W)^&HiD2Vg6Y%liJXWSZA%X5hjKR z>=>d{c{AHWHMmT%CeEBS+}yg5L9bc6_Jl9GeY0#Z(Q`t2ji%QVG*Zr>*OzHR)_Q2Or_q4xV0`p_WQR&TIz)xfLUlI6JdJ{4jgcW zqj#}5bWft@jWK_sewbDwxM~(BPIwi{Y(oC*5*B_Q8(sC=3OUZV2DxL2alK}$Wq~%g zp-5kK5-Lj@$<_gAsrh#AJ_U?JOPq57ju}o#`%B^Fn{X{}7KyXpbW}gzp;XHKfD8~H zs(KTBpKk=bE>!Et&$IA*$4G?fx=!$f&z(E9wTW6y6ChdQA!v?=(S_+YOQwcomzTFvf#k>y0?9z8_U*+yXPgr@ z;Xsj#eFb#4459^Z^6}ZZwF#t?Xyh)n&vUe9_E1t= zMj^`L7Qjdk#CGy)qRLWHn8QBnLCi_Sqa-%6F!8~;z^J-vzZXZ4V~C!4-@biWosjK@ zZTP~jPak?~Du+*|2y^@kIw?~`*gplnM*(pE-aTXnYa+SEIW)8U`$oe|L&%!IBh$Zh z%r@y)`7GJ|w=vVma>qlI?nK}U*hdlzsCZ{!3#ezdAxzfRr&+ZgmB!iD_^yq0kuz0TN+O<(grCm7O8ixDyf~_w!iUJ6Ic@P2zFYWN z5rUq%bLX0HLE#ciY%ds8 zA}uFkd0-pe0UH!5@gR@Q(?LQ)0<1lt4+{5F_n(#2_FciMR(3yc=72I~HE74#ZmIg8 zx~2DQ2VM=$mNieHj?nad4lCPio3!mmY4aA%+1d`;v$Jz78gNHO=hLU=I>O)q4%h7I zhV*4W-R1iQ)oV{r4<~Vwpvk!til@pq7qpRU7jip>6@7#mrPEuixdP%1^!!|#I*5>6 zc)RvI<-ZM0#3d5<*O93bQOb7kD>XA2B3r62Q2P%rhbFhv0uqxXhmdW+phVA^`pe+T6Ag7jhEJ3O*U2rW6>E#lM4 ze`yub6m7T7){OQP%)mr=>5i#op6nW1X+tj>yW1K3ibI0yb!l~d7sRP^U z_qP~udDL8R;IiwXoiA*>`)GCKhkMjxbbVRX)keQxzZpJwl4>^2cjx?^W5ymcmiseT z$zHj_@ELMVs7Y;}91?ex$y+sA;x-}!)yn^ZYdl3{bZ+2DAfVLLR8^=!5n|Z=Ed|Xs zqkvpQ#1D|nx%d1PLe?lKCc5Y($hbL|1(72YZ_O+(3ws!&7Ug6JcRL>l`RAIJ5u z;i3TViQNrq6@N4mx}`nv{(+_|L66?|^9$b~WYBp{_WKjy5t~!6O+vR5OTGt#T{ZDG zm*`C^1HVr+v`p8oCdYE=xm#4E=RoP>&+*bJEE?ju5^TLLLi zwcgBx2I)G0Sh2k`^zB=9d$s?cwEz{cwZSKs06X<2$T(4?%aWrCKNNC$0(FFhqUW~e z>*UZV2nRZy`np|KNl{VpayxX+xxoChzEMN7S63EsikRHT%><{T$~1!UxEs7)+FC@2 z@u7|q^Gp`H%A@%!aJ{fK*0~gGLFk2n>7t9)418N%5My&gfSTve`96#@PE24l-UMOQ^X+hw1>~OAQGcqDl4SN z@_}3rpq)B(`~3OyocUx@gR3BHWzcw8$JX_Z7|`S!4p59e0rv2Yp3^3<`9faZZ+|M zf_c4YXeen4^o!g`-UqnGU^d!wtnrRe2lw{bkqct7`? zM-md2t*a|Kv=&HqqYaT^$;E%M*N}s=t2$9jj07%>OZWgi160Q9{o{luM>iY3s&FJ= z#>2gbWWRr24!wYOkq+Hi4PH28@88Qn;)AQ@1OE!Whc|sIt{YZknM1J%W27~U z{=FaX1}~-L>`=FnM`+{QfpL?qLf*Fh_UQm&r)v-xpIf(`2uLBW4EXaN04+kCc^qJ# zaD_yF>NfCZop(MlIfaRk>qAXKbbZ@p$8SKF#VHH`*aA0rfcsET%YM^U+fG#g?yctG z=}&0NvO0uAck{*#tNb>siwbE-B2Ti3+}TQW9)-Ue8WCarqJvkj+}2R6IE+7-w>K=Y zYkU8oU6+#*_9$D2lD!TMVHBY%C>yl9LEC=-S)BCc%XzBu(W74GE%}Ma6ahp(FgQA@ z0dd(y(*=}xoqX3bvSSCHi<-MCZ&&E6ek9~k_0Eq6vlF(nFY_E;b&&Fcf%-8FlN_K5 zuIW}oYvf>no+&4sF?t2R~o!{vHEdmP30ObZE0RoexGPYx1-s4eSP$6I+SnSxS<5)TH(57l(o5T4JtDZZLPUd({@}GT0UA$fF0S@ zJ@zg_iBY|qJ*)i~27bxO$wV<>QjDH7tgoY^4nIEKG!2e!%m(Pu4OmKHyfTQte<7~@ zmq7+`c9dvT=}~yZtq)^_1>^bCjNdcQipatEcp7T5#E_sMzU9l8L(2YE{Iqg<3IyyB z=UQ?v^vp0C!ythT>0FF4rWM6A7ev}C

PH1=1nGh>eLk4hp&~5EuxQBC5cx2p`nS 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg b/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg index 43cae3870773..bfee0626196e 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg @@ -1,562 +1,1207 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index 78853dfd47e6..200fad33461a 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -663,9 +663,9 @@ RendererAgg::draw_markers(const Py::Tuple& args) PathIterator path(path_obj); transformed_path_t path_transformed(path, trans); snap_t path_snapped(path_transformed, - gc.snap_mode, + SNAP_TRUE, path.total_vertices(), - 1.0); + 0.0); curve_t path_curve(path_snapped); path_curve.rewind(0); From 85b5e284b210f468146076713ea1f2dcd871b119 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 14 Jul 2011 15:46:31 -0400 Subject: [PATCH 038/214] Update Gtk and Qt4 backends to be aware of the new location of the marker definitions. --- lib/matplotlib/backends/backend_gtk.py | 3 ++- .../backends/qt4_editor/figureoptions.py | 26 ++----------------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index 142292edd849..077711a8f9dd 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -32,6 +32,7 @@ def fn_name(): return sys._getframe(1).f_code.co_name from matplotlib.widgets import SubplotTool from matplotlib import lines +from matplotlib import markers from matplotlib import cbook from matplotlib import verbose @@ -1076,7 +1077,7 @@ class DialogLineprops: linestyled = dict([ (s,i) for i,s in enumerate(linestyles)]) - markers = [m for m in lines.Line2D.markers if cbook.is_string_like(m)] + markers = [m for m in markers.MarkerStyle.markers if cbook.is_string_like(m)] markerd = dict([(s,i) for i,s in enumerate(markers)]) diff --git a/lib/matplotlib/backends/qt4_editor/figureoptions.py b/lib/matplotlib/backends/qt4_editor/figureoptions.py index 81a5605d279b..a42aed12e007 100644 --- a/lib/matplotlib/backends/qt4_editor/figureoptions.py +++ b/lib/matplotlib/backends/qt4_editor/figureoptions.py @@ -10,6 +10,7 @@ import matplotlib.backends.qt4_editor.formlayout as formlayout from matplotlib.backends.qt4_compat import QtGui +from matplotlib import markers def get_icon(name): import matplotlib @@ -25,30 +26,7 @@ def get_icon(name): 'none': 'None', } -MARKERS = { - 'none': 'None', - 'o': 'circles', - '^': 'triangle_up', - 'v': 'triangle_down', - '<': 'triangle_left', - '>': 'triangle_right', - 's': 'square', - '+': 'plus', - 'x': 'cross', - '*': 'star', - 'D': 'diamond', - 'd': 'thin_diamond', - '1': 'tripod_down', - '2': 'tripod_up', - '3': 'tripod_left', - '4': 'tripod_right', - 'h': 'hexagon', - 'H': 'rotated_hexagon', - 'p': 'pentagon', - '|': 'vertical_line', - '_': 'horizontal_line', - '.': 'dots', - } +MARKERS = markers.MarkerStyle.markers COLORS = {'b': '#0000ff', 'g': '#00ff00', 'r': '#ff0000', 'c': '#ff00ff', 'm': '#ff00ff', 'y': '#ffff00', 'k': '#000000', 'w': '#ffffff'} From 6fe5fa03e8608949cb08a485a4d6adf9247a5ffb Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 15 Jul 2011 13:59:54 -0400 Subject: [PATCH 039/214] Make scatter use the new marker class. Add a "scatter_symbol" example. Make legend support the new kind of scatter. --- CHANGELOG | 9 + examples/pylab_examples/scatter_symbol.py | 14 + lib/matplotlib/axes.py | 119 +----- lib/matplotlib/collections.py | 20 +- lib/matplotlib/legend.py | 3 +- lib/matplotlib/legend_handler.py | 12 + lib/matplotlib/lines.py | 6 + lib/matplotlib/markers.py | 435 +++++++++++++--------- 8 files changed, 341 insertions(+), 277 deletions(-) create mode 100644 examples/pylab_examples/scatter_symbol.py diff --git a/CHANGELOG b/CHANGELOG index 56e2a26e8f60..c2861a05fd63 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,12 @@ +2001-07-15 The set of markers available in the plot() and scatter() + commands has been unified. In general, this gives more + options to both than were previously available, however, + there is one backward-incompatible change to the markers in + scatter: + + "d" used to mean "diamond", it now means "narrow + diamond", now "D" can be used for a "diamond". + 2011-07-10 Fixed argument handling error in tripcolor/triplot/tricontour, issue #203. - IMT diff --git a/examples/pylab_examples/scatter_symbol.py b/examples/pylab_examples/scatter_symbol.py new file mode 100644 index 000000000000..bc805afbed0e --- /dev/null +++ b/examples/pylab_examples/scatter_symbol.py @@ -0,0 +1,14 @@ +from matplotlib import pyplot as plt +import numpy as np +import matplotlib + +x = np.arange(0.0, 50.0, 2.0) +y = x ** 1.3 + np.random.rand(*x.shape) * 30.0 +s = np.random.rand(*x.shape) * 800 + 500 + +plt.scatter(x, y, s, c="g", alpha=0.5, marker=r'$\clubsuit$', + label="Luck") +plt.xlabel("Leprechauns") +plt.ylabel("Gold") +plt.legend(loc=2) +plt.show() diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index c6dd94a9c47e..f61cccd76ade 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -22,6 +22,7 @@ import matplotlib.image as mimage import matplotlib.legend as mlegend import matplotlib.lines as mlines +import matplotlib.markers as mmarkers import matplotlib.mlab as mlab import matplotlib.path as mpath import matplotlib.patches as mpatches @@ -5651,23 +5652,8 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, *marker*: can be one of: - ======= ============== - Value Description - ======= ============== - ``'s'`` square - ``'o'`` circle - ``'^'`` triangle up - ``'>'`` triangle right - ``'v'`` triangle down - ``'<'`` triangle left - ``'d'`` diamond - ``'p'`` pentagon - ``'h'`` hexagon - ``'8'`` octagon - ``'+'`` plus - ``'x'`` cross - ======= ============== - + # TODO: Use documentation in MarkerStyle + The marker can also be a tuple (*numsides*, *style*, *angle*), which will create a custom, regular symbol. @@ -5749,21 +5735,6 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, if not self._hold: self.cla() - syms = { # a dict from symbol to (numsides, angle) - 's' : (4,math.pi/4.0,0), # square - 'o' : (0,0,3), # circle - '^' : (3,0,0), # triangle up - '>' : (3,math.pi/2.0,0), # triangle right - 'v' : (3,math.pi,0), # triangle down - '<' : (3,3*math.pi/2.0,0), # triangle left - 'd' : (4,0,0), # diamond - 'p' : (5,0,0), # pentagon - 'h' : (6,0,0), # hexagon - '8' : (8,0,0), # octagon - '+' : (4,0,2), # plus - 'x' : (4,math.pi/4.0,2) # cross - } - self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs) x = self.convert_xunits(x) y = self.convert_yunits(y) @@ -5814,87 +5785,21 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, marker = (verts, 0) verts = None - if is_string_like(marker): - # the standard way to define symbols using a string character - sym = syms.get(marker) - if sym is None and verts is None: - raise ValueError('Unknown marker symbol to scatter') - numsides, rotation, symstyle = syms[marker] - - elif iterable(marker): - # accept marker to be: - # (numsides, style, [angle]) - # or - # (verts[], style, [angle]) - - if len(marker)<2 or len(marker)>3: - raise ValueError('Cannot create markersymbol from marker') - - if cbook.is_numlike(marker[0]): - # (numsides, style, [angle]) - - if len(marker)==2: - numsides, rotation = marker[0], 0. - elif len(marker)==3: - numsides, rotation = marker[0], marker[2] - sym = True - - if marker[1] in (1,2,3): - symstyle = marker[1] - - else: - verts = np.asarray(marker[0]) - - if sym is not None: - if symstyle==0: - collection = mcoll.RegularPolyCollection( - numsides, rotation, scales, - facecolors = colors, - edgecolors = edgecolors, - linewidths = linewidths, - offsets = zip(x,y), - transOffset = self.transData, - ) - elif symstyle==1: - collection = mcoll.StarPolygonCollection( - numsides, rotation, scales, - facecolors = colors, - edgecolors = edgecolors, - linewidths = linewidths, - offsets = zip(x,y), - transOffset = self.transData, - ) - elif symstyle==2: - collection = mcoll.AsteriskPolygonCollection( - numsides, rotation, scales, - facecolors = colors, - edgecolors = 'face', - linewidths = linewidths, - offsets = zip(x,y), - transOffset = self.transData, - ) - elif symstyle==3: - collection = mcoll.CircleCollection( - scales, - facecolors = colors, - edgecolors = edgecolors, - linewidths = linewidths, - offsets = zip(x,y), - transOffset = self.transData, - ) - else: - rescale = np.sqrt(max(verts[:,0]**2+verts[:,1]**2)) - verts /= rescale - - collection = mcoll.PolyCollection( - (verts,), scales, + marker_obj = mmarkers.MarkerStyle(marker) + path = marker_obj.get_path().transformed( + marker_obj.get_transform()) + if not marker_obj.is_filled(): + edgecolors = 'face' + + collection = mcoll.PathCollection( + (path,), scales, facecolors = colors, edgecolors = edgecolors, linewidths = linewidths, offsets = zip(x,y), transOffset = self.transData, ) - collection.set_transform(mtransforms.IdentityTransform()) + collection.set_transform(mtransforms.IdentityTransform()) collection.set_alpha(alpha) collection.update(kwargs) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index b0846cf927e6..2d08e37aeb86 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -574,7 +574,7 @@ class PathCollection(Collection): This is the most basic :class:`Collection` subclass. """ @docstring.dedent_interpd - def __init__(self, paths, **kwargs): + def __init__(self, paths, sizes=None, **kwargs): """ *paths* is a sequence of :class:`matplotlib.path.Path` instances. @@ -584,11 +584,25 @@ def __init__(self, paths, **kwargs): Collection.__init__(self, **kwargs) self.set_paths(paths) - + self._sizes = sizes def set_paths(self, paths): self._paths = paths - + + def get_paths(self): + return self._paths + + def get_sizes(self): + return self._sizes + + @allow_rasterization + def draw(self, renderer): + if self._sizes is not None: + self._transforms = [ + transforms.Affine2D().scale( + (np.sqrt(x) * self.figure.dpi / 72.0)) + for x in self._sizes] + return Collection.draw(self, renderer) class PolyCollection(Collection): @docstring.dedent_interpd diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 9a70e8df3ab5..3e9ccdfff3be 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -23,7 +23,7 @@ from matplotlib.lines import Line2D from matplotlib.patches import Patch, Rectangle, Shadow, FancyBboxPatch from matplotlib.collections import LineCollection, RegularPolyCollection, \ - CircleCollection + CircleCollection, PathCollection from matplotlib.transforms import Bbox, BboxBase, TransformedBbox, BboxTransformTo, BboxTransformFrom from matplotlib.offsetbox import HPacker, VPacker, TextArea, DrawingArea, DraggableOffsetBox @@ -481,6 +481,7 @@ def _approx_text_height(self, renderer=None): CircleCollection:legend_handler.HandlerCircleCollection(), BarContainer:legend_handler.HandlerPatch(update_func=legend_handler.update_from_first_child), tuple:legend_handler.HandlerTuple(), + PathCollection:legend_handler.HandlerPathCollection() } # (get|set|update)_default_handler_maps are public interfaces to diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 94ee6e29b264..baa3251b1045 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -362,7 +362,19 @@ def create_artists(self, legend, orig_handle, return [p] +class HandlerPathCollection(HandlerRegularPolyCollection): + """ + Handler for PathCollections, which are used by scatter + """ + def create_collection(self, orig_handle, sizes, offsets, transOffset): + p = type(orig_handle)([orig_handle.get_paths()[0]], + sizes=sizes, + offsets=offsets, + transOffset=transOffset, + ) + return p + class HandlerCircleCollection(HandlerRegularPolyCollection): """ Handler for CircleCollections diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 18c906ae22f1..f799caddc5df 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -103,6 +103,12 @@ class Line2D(Artist): # Need a list ordered with long names first: drawStyleKeys = _drawStyles_l.keys() + _drawStyles_s.keys() + # Referenced here to maintain API. These are defined in + # MarkerStyle + markers = MarkerStyle.markers + filled_markers = MarkerStyle.filled_markers + fillStyles = MarkerStyle.fillstyles + zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index aa3fa5a7ba05..247b40640ff0 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -6,7 +6,8 @@ import numpy as np -from cbook import is_math_text +from cbook import is_math_text, is_string_like, is_numlike, iterable +from matplotlib import rcParams from path import Path from transforms import IdentityTransform, Affine2D @@ -14,8 +15,6 @@ (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) -# TODO: Cache the marker path within the object - class MarkerStyle: style_table = """ ======================== ===================================================== @@ -23,9 +22,11 @@ class MarkerStyle: ======================== ===================================================== %s ``'$...$'`` render the string using mathtext -(numsides, style, angle) where style is 1: star, 2: asterisk, 3: circle -(verts, 0) where verts is a list of (x, y) pairs in range (0, 1) +(numsides, style, angle) see below +verts where verts is a list of (x, y) pairs in range (0, 1) ======================== ===================================================== + +TODO: Describe tuple form """ # TODO: Automatically generate this @@ -43,6 +44,7 @@ class MarkerStyle: '2' : 'tri_up', '3' : 'tri_left', '4' : 'tri_right', + '8' : 'octagon', 's' : 'square', 'p' : 'pentagon', '*' : 'star', @@ -67,9 +69,11 @@ class MarkerStyle: '' : 'nothing' } - filled_markers = ('o', '^', 'v', '<', '>', - 's', 'd', 'D', 'h', 'H', 'p', '*') - + # Just used for informational purposes. is_filled() + # is calculated in the _set_* functions. + filled_markers = ( + 'o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd') + fillstyles = ('full', 'left' , 'right' , 'bottom' , 'top') # TODO: Is this ever used as a non-constant? @@ -81,17 +85,20 @@ def __init__(self, marker=None, fillstyle='full'): self.set_fillstyle(fillstyle) def _recache(self): - (self._path, self._transform, - self._alt_path, self._alt_transform, - self._snap_threshold) = self._marker_function() + self._path = Path(np.empty((0,2))) + self._transform = IdentityTransform() + self._alt_path = None + self._alt_transform = None + self._snap_threshold = None + self._filled = True + self._marker_function() def __nonzero__(self): return len(self._path.vertices) def is_filled(self): - return (self._marker in self.filled_markers - or is_math_text(self._marker)) - + return self._filled + def get_fillstyle(self): return self._fillstyle @@ -105,16 +112,24 @@ def get_marker(self): return self._marker def set_marker(self, marker): - if marker in self.markers: - self._marker = marker + if (iterable(marker) and len(marker) in (2, 3) and + marker[1] in (0, 1, 2, 3)): + self._marker_function = self._set_tuple_marker + elif marker in self.markers: self._marker_function = getattr( - self, '_get_' + self.markers[marker]) - elif is_math_text(marker): - self._marker = marker - self._marker_function = self._get_mathtext_path + self, '_set_' + self.markers[marker]) + elif is_string_like(marker) and is_math_text(marker): + self._marker_function = self._set_mathtext_path + elif isinstance(marker, Path): + self._marker_function = self._set_path_marker else: - raise ValueError('Unrecognized marker style %s' % marker) + try: + path = Path(marker) + self._marker_function = self._set_vertices + except: + raise ValueError('Unrecognized marker style %s' % marker) + self._marker = marker self._recache() def get_path(self): @@ -132,10 +147,47 @@ def get_alt_transform(self): def get_snap_threshold(self): return self._snap_threshold - def _get_nothing(self): - return Path(np.empty((0,2))), IdentityTransform(), None, None, False + def _set_nothing(self): + self._filled = False + + def _set_custom_marker(self, path): + verts = path.vertices + rescale = np.sqrt(max(np.max(verts[:,0]**2), + np.max(verts[:,1]**2))) + self._transform = Affine2D().scale(1.0 / rescale) + self._path = path + + def _set_path_marker(self): + self._set_custom_marker(self._marker) + + def _set_vertices(self): + path = Path(verts) + self._set_custom_marker(path) - def _get_mathtext_path(self): + def _set_tuple_marker(self): + marker = self._marker + if is_numlike(marker[0]): + if len(marker) == 2: + numsides, rotation = marker[0], 0.0 + elif len(marker) == 3: + numsides, rotation = marker[0], marker[2] + symstyle = marker[1] + if symstyle == 0: + self._path = Path.unit_regular_polygon(numsides) + elif symstyle == 1: + self._path = Path.unit_regular_star(numsides) + elif symstyle == 2: + self._path = Path.unit_regular_asterisk(numsides) + self._filled = False + elif symstyle == 3: + self._path = Path.unit_circle() + self._transform = Affine2D().scale(0.5).rotate_deg(rotation) + else: + verts = np.asarray(marker[0]) + path = Path(verts) + self._set_custom_marker(path) + + def _set_mathtext_path(self): """ Draws mathtext markers '$...$' using TextPath object. @@ -143,7 +195,8 @@ def _get_mathtext_path(self): """ from matplotlib.patches import PathPatch from matplotlib.text import TextPath - + from matplotlib.font_manager import FontProperties + # again, the properties could be initialised just once outside # this function # Font size is irrelevant here, it will be rescaled based on @@ -152,24 +205,25 @@ def _get_mathtext_path(self): text = TextPath(xy=(0,0), s=self.get_marker(), fontproperties=props, usetex=rcParams['text.usetex']) if len(text.vertices) == 0: - return text, IdentityTransform(), False + return xmin, ymin = text.vertices.min(axis=0) xmax, ymax = text.vertices.max(axis=0) width = xmax - xmin height = ymax - ymin max_dim = max(width, height) - path_trans = Affine2D() \ + self._transform = Affine2D() \ .translate(-xmin + 0.5 * -width, -ymin + 0.5 * -height) \ .scale(1.0 / max_dim) + self._path = text + self._snap = False - return text, path_trans, None, None, False - - def _get_circle(self, reduction = 1.0): - transform = Affine2D().scale(0.5 * reduction) + def _set_circle(self, reduction = 1.0): + self._transform = Affine2D().scale(0.5 * reduction) + self._snap_threshold = 3.0 fs = self.get_fillstyle() if fs=='full': - return Path.unit_circle(), transform, None, None, 3.0 + self._path = Path.unit_circle() else: # build a right-half circle if fs=='bottom': rotate = 270. @@ -177,16 +231,17 @@ def _get_circle(self, reduction = 1.0): elif fs=='left': rotate = 180. else: rotate = 0. - half = Path.unit_circle_righthalf() - transform = transform.rotate_deg(rotate) - alt_transform = transform.rotate_deg(180.) - return half, transform, half, alt_transform, 3.0 - - def _get_pixel(self): - return Path.unit_rectangle(), Affine2D().translate(-0.5, 0.5), None, None, False + self._path = self._alt_path = Path.unit_circle_righthalf() + self._transform.rotate_deg(rotate) + self._alt_transform = self._transform.frozen().rotate_deg(180.) - def _get_point(self): - return self._get_circle(reduction = self._point_size_reduction) + def _set_pixel(self): + self._path = Path.unit_rectangle() + self._transform = Affine2D().translate(-0.5, 0.5) + self._snap_threshold = False + + def _set_point(self): + self._set_circle(reduction = self._point_size_reduction) _triangle_path = Path( [[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]], @@ -204,59 +259,52 @@ def _get_point(self): _triangle_path_r = Path( [[0.0, 1.0], [0.0, -1.0], [1.0, -1.0], [0.0, 1.0]], [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - def _get_triangle(self, rot, skip): - direction_map = { - 'up': (0.0, 0), - 'down': (180.0, 2), - 'left': (90.0, 3), - 'right': (270.0, 1) - } - rot, skip = direction_map[direction] - transform = Affine2D().scale(0.5, 0.5).rotate_deg(rot) + def _set_triangle(self, rot, skip): + self._transform = Affine2D().scale(0.5, 0.5).rotate_deg(rot) + self._snap_threshold = 5.0 fs = self.get_fillstyle() if fs=='full': - return self._triangle_path, transform, None, None, 5.0 + self._path = self._triangle_path else: - rgbFace_alt = self._get_rgb_face(alt=True) - mpaths = [self._triangle_path_u, self._triangle_path_l, self._triangle_path_d, self._triangle_path_r] if fs=='top': - mpath = mpaths[(0+skip) % 4] - mpath_alt = mpaths[(2+skip) % 4] + self._path = mpaths[(0+skip) % 4] + self._alt_path = mpaths[(2+skip) % 4] elif fs=='bottom': - mpath = mpaths[(2+skip) % 4] - mpath_alt = mpaths[(0+skip) % 4] + self._path = mpaths[(2+skip) % 4] + self._alt_path = mpaths[(0+skip) % 4] elif fs=='left': - mpath = mpaths[(1+skip) % 4] - mpath_alt = mpaths[(3+skip) % 4] + self._path = mpaths[(1+skip) % 4] + self._alt_path = mpaths[(3+skip) % 4] else: - mpath = mpaths[(3+skip) % 4] - mpath_alt = mpaths[(1+skip) % 4] + self._path = mpaths[(3+skip) % 4] + self._alt_path = mpaths[(1+skip) % 4] - return mpath, transform, mpath_alt, transform, 5.0 + self._alt_transform = self._transform - def _get_triangle_up(self): - self._get_triangle(0.0, 0) + def _set_triangle_up(self): + return self._set_triangle(0.0, 0) - def _get_triangle_down(self): - self._get_triangle(180.0, 2) + def _set_triangle_down(self): + return self._set_triangle(180.0, 2) - def _get_triangle_left(self): - self._get_triangle(90.0, 3) + def _set_triangle_left(self): + return self._set_triangle(90.0, 3) - def _get_triangle_right(self): - self._get_triangle(270.0, 1) + def _set_triangle_right(self): + return self._set_triangle(270.0, 1) - def _get_square(self): - transform = Affine2D().translate(-0.5, -0.5) + def _set_square(self): + self._transform = Affine2D().translate(-0.5, -0.5) + self._snap_threshold = 2.0 fs = self.get_fillstyle() if fs=='full': - return Path.unit_rectangle(), transform, None, None, 2.0 + self._path = Path.unit_rectangle() else: # build a bottom filled square out of two rectangles, one # filled. Use the rotation to support left, right, bottom @@ -266,42 +314,42 @@ def _get_square(self): elif fs=='left': rotate = 270. else: rotate = 90. - bottom = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 0.5], [0.0, 0.5], [0.0, 0.0]]) - top = Path([[0.0, 0.5], [1.0, 0.5], [1.0, 1.0], [0.0, 1.0], [0.0, 0.5]]) - transform = transform.rotate_deg(rotate) - return bottom, transform, top, transform, 2.0 + self._path = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 0.5], [0.0, 0.5], [0.0, 0.0]]) + self._alt_path = Path([[0.0, 0.5], [1.0, 0.5], [1.0, 1.0], [0.0, 1.0], [0.0, 0.5]]) + self._transform.rotate_deg(rotate) + self._alt_transform = self._transform - def _get_diamond(self): - transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45) + def _set_diamond(self): + self._transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45) + self._snap_threshold = 5.0 fs = self.get_fillstyle() if fs=='full': - return Path.unit_rectangle(), transform, None, None, 5.0 + self._path = Path.unit_rectangle() else: - right = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]]) - left = Path([[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [0.0, 0.0]]) + self._path = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]]) + self._alt_path = Path([[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [0.0, 0.0]]) if fs=='bottom': rotate = 270. elif fs=='top': rotate = 90. elif fs=='left': rotate = 180. else: rotate = 0. - transform = transform.rotate_deg(rotate) - - return right, transform, left, transform, 5.0 - - def _get_thin_diamond(self): - right, transform, left, _, snap = self._get_diamond() - transform = transform.scale(0.6, 1.0) - return right, transform, left, transform, 3.0 + self._transform.rotate_deg(rotate) + self._alt_transform = self._transform + + def _set_thin_diamond(self): + self._set_diamond() + self._transform.scale(0.6, 1.0) - def _get_pentagon(self): - transform = Affine2D().scale(0.5) + def _set_pentagon(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 5.0 + polypath = Path.unit_regular_polygon(5) - fs = self.get_fillstyle() if fs == 'full': - return polypath, tranform, None, None, 5.0 + self._path = polypath else: verts = polypath.vertices @@ -319,17 +367,19 @@ def _get_pentagon(self): mpath, mpath_alt = left, right else: mpath, mpath_alt = right, left + self._path = mpath + self._alt_path = mpath_alt + self._alt_transform = self._transform - return mpath, transform, mpath_alt, transform, 5.0 + def _set_star(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 5.0 - def _get_star(self): - transform = Affine2D().scale(0.5) fs = self.get_fillstyle() - polypath = Path.unit_regular_star(5, innerCircle=0.381966) if fs == 'full': - return polypath, transform, None, None, 5.0 + self._path = polypath else: verts = polypath.vertices @@ -346,17 +396,19 @@ def _get_star(self): mpath, mpath_alt = left, right else: mpath, mpath_alt = right, left + self._path = mpath + self._alt_path = mpath_alt + self._alt_transform = self._transform - return mpath, transform, mpath_alt, transform, 5.0 - - def _get_hexagon1(self): - transform = Affine2D().scale(0.5) + def _set_hexagon1(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 5.0 + fs = self.get_fillstyle() - polypath = Path.unit_regular_polygon(6) if fs == 'full': - return polypath, transform, None, None, 5.0 + self._path = polypath else: verts = polypath.vertices @@ -376,16 +428,19 @@ def _get_hexagon1(self): else: mpath, mpath_alt = right, left - return mpath, transform, mpath_alt, transform, 5.0 + self._path = mpath + self._alt_path = mpath_alt + self._alt_transform = self._transform - def _get_hexagon2(self): - transform = Affine2D().scale(0.5).rotate_deg(30) + def _set_hexagon2(self): + self._transform = Affine2D().scale(0.5).rotate_deg(30) + self._snap_threshold = 5.0 + fs = self.get_fillstyle() - polypath = Path.unit_regular_polygon(6) if fs == 'full': - return polypath, transform, None, None, 5.0 + self._path = polypath else: verts = polypath.vertices @@ -405,42 +460,71 @@ def _get_hexagon2(self): else: mpath, mpath_alt = right, left - return mpath, transform, mpath_alt, transform, 5.0 + self._path = mpath + self._alt_path = mpath_alt + self._alt_transform = self._transform - _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) - def _get_vline(self): - transform = Affine2D().scale(0.5) - return self._line_marker_path, transform, None, None, 1.0 + def _set_octagon(self): + self._transform = Affine2D().scale(0.5).rotate_deg(22.5) + self._snap_threshold = 5.0 + + fs = self.get_fillstyle() + polypath = Path.unit_regular_polygon(8) - def _get_hline(self): - transform = Affine2D().scale(0.5).rotate_deg(90) - return self._line_marker_path, transform, None, None, 1.0 + if fs == 'full': + self._path = polypath + else: + # TODO: Implement partially-filled octagons + self._path = polypath + + _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) + def _set_vline(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 1.0 + self._filled = False + self._path = _line_marker_path + + def _set_hline(self): + self._transform = Affine2D().scale(0.5).rotate_deg(90) + self._snap_threshold = 1.0 + self._filled = False + self._path = _line_marker_path _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) - def _get_tickleft(self): - transform = Affine2D().scale(-1.0, 1.0) - return self._tickhoriz_path, transform, None, None, 1.0 - - def _get_tickright(self): - transform = Affine2D().scale(1.0, 1.0) - return self._tickhoriz_path, transform, None, None, 1.0 + def _set_tickleft(self): + self._transform = Affine2D().scale(-1.0, 1.0) + self._snap_threshold = 1.0 + self._filled = False + self._path = self._tickhoriz_path + + def _set_tickright(self): + self._transform = Affine2D().scale(1.0, 1.0) + self._snap_threshold = 1.0 + self._filled = False + self._path = self._tickhoriz_path _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) - def _get_tickup(self): - transform = Affine2D().scale(1.0, 1.0) - return self._tickvert_path, transform, None, None, 1.0 + def _set_tickup(self): + self._transform = Affine2D().scale(1.0, 1.0) + self._snap_threshold = 1.0 + self._filled = False + self._path = self._tickvert_path - def _get_tickdown(self): - transform = Affine2D().scale(1.0, -1.0) - return self._tickvert_path, transform, None, None, 1.0 + def _set_tickdown(self): + self._transform = Affine2D().scale(1.0, -1.0) + self._snap_threshold = 1.0 + self._filled = False + self._path = self._tickvert_path _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) - def _get_plus(self): - transform = Affine2D().scale(0.5) - return self._plus_path, transform, None, None, 1.0 + def _set_plus(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 1.0 + self._filled = False + self._path = self._plus_path _tri_path = Path([[0.0, 0.0], [0.0, -1.0], [0.0, 0.0], [0.8, 0.5], @@ -448,45 +532,64 @@ def _get_plus(self): [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) - def _draw_tri_down(self): - transform = Affine2D().scale(0.5) - return self._tri_path, transform, None, None, 5.0 - - def _draw_tri_up(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5).rotate_deg(90) - return self._tri_path, transform, None, None, 5.0 - - def _draw_tri_left(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5).rotate_deg(270) - return self._tri_path, transform, None, None, 5.0 - - def _draw_tri_right(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5).rotate_deg(180) + def _set_tri_down(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 5.0 + self._filled = False + self._path = self._tri_path + + def _set_tri_up(self): + self._transform = Affine2D().scale(0.5).rotate_deg(90) + self._snap_threshold = 5.0 + self._filled = False + self._path = self._tri_path + + def _set_tri_left(self): + self._transform = Affine2D().scale(0.5).rotate_deg(270) + self._snap_threshold = 5.0 + self._filled = False + self._path = self._tri_path + + def _set_tri_right(self): + self._transform = Affine2D().scale(0.5).rotate_deg(180) + self._snap_threshold = 5.0 + self._filled = False + self._path = self._tri_path _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) - def _draw_caretdown(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5) - return self._caret_path, transform, None, None, 3.0 - - def _draw_caretup(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5).rotate_deg(180) - return self._caret_path, transform, None, None, 3.0 - - def _draw_caretleft(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5).rotate_deg(270) - return self._caret_path, transform, None, None, 3.0 - - def _draw_caretright(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5).rotate_deg(90) - return self._caret_path, transform, None, None, 3.0 + def _set_caretdown(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 3.0 + self._filled = False + self._path = self._caret_path + + def _set_caretup(self): + self._transform = Affine2D().scale(0.5).rotate_deg(180) + self._snap_threshold = 3.0 + self._filled = False + self._path = self._caret_path + + def _set_caretleft(self): + self._transform = Affine2D().scale(0.5).rotate_deg(270) + self._snap_threshold = 3.0 + self._filled = False + self._path = self._caret_path + + def _set_caretright(self): + self._transform = Affine2D().scale(0.5).rotate_deg(90) + self._snap_threshold = 3.0 + self._filled = False + self._path = self._caret_path _x_path = Path([[-1.0, -1.0], [1.0, 1.0], [-1.0, 1.0], [1.0, -1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) - def _draw_x(self, renderer, gc, path, path_trans): - transform = Affine2D().scale(0.5) - return self._x_path, transform, None, None, 3.0 + def _set_x(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 3.0 + self._filled = False + self._path = self._x_path _styles = [(repr(x), y) for x, y in MarkerStyle.markers.items()] _styles.sort() From 83da58e6452f2b580bd9dfb1170dec2f8468b25c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 15 Jul 2011 14:25:18 -0400 Subject: [PATCH 040/214] Implement fill style for octagon marker. --- lib/matplotlib/markers.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index 247b40640ff0..b7ee99c8814a 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -465,18 +465,29 @@ def _set_hexagon2(self): self._alt_transform = self._transform def _set_octagon(self): - self._transform = Affine2D().scale(0.5).rotate_deg(22.5) + self._transform = Affine2D().scale(0.5) self._snap_threshold = 5.0 fs = self.get_fillstyle() polypath = Path.unit_regular_polygon(8) if fs == 'full': + self._transform.rotate_deg(22.5) self._path = polypath else: - # TODO: Implement partially-filled octagons - self._path = polypath - + x = np.sqrt(2.)/4. + half = Path([[0, -1], [0, 1], [-x, 1], [-1, x], + [-1, -x], [-x, -1], [0, -1]]) + + if fs=='bottom': rotate = 90. + elif fs=='top': rotate = 270. + elif fs=='right': rotate = 180. + else: rotate = 0. + + self._transform.rotate_deg(rotate) + self._path = self._alt_path = half + self._alt_transform = self._transform.frozen().rotate_deg(180.0) + _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) def _set_vline(self): self._transform = Affine2D().scale(0.5) From 6ece5baa29a344281ce30987a32a95722256c0fb Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 15 Jul 2011 14:20:40 -0500 Subject: [PATCH 041/214] Fixed minor typo in the __str__ representation of a Text object. --- lib/matplotlib/text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index ba5aa2b8d6e9..73df0304b764 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -147,7 +147,7 @@ class Text(Artist): cached = maxdict(50) def __str__(self): - return "Text(%g,%g,%s)"%(self._y,self._y,repr(self._text)) + return "Text(%g,%g,%s)"%(self._x,self._y,repr(self._text)) def __init__(self, x=0, y=0, text='', From 243d78daa264a1e02b3f6e147f8b1c9962652bb7 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 15 Jul 2011 16:04:25 -0400 Subject: [PATCH 042/214] Fix docstrings about refactored markers. --- lib/matplotlib/axes.py | 28 +------------------- lib/matplotlib/lines.py | 9 ++++--- lib/matplotlib/markers.py | 55 ++++++++++++++++++++++++++++++--------- 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f61cccd76ade..cd23f1c72df4 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -5652,33 +5652,7 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, *marker*: can be one of: - # TODO: Use documentation in MarkerStyle - - The marker can also be a tuple (*numsides*, *style*, - *angle*), which will create a custom, regular symbol. - - *numsides*: - the number of sides - - *style*: - the style of the regular symbol: - - ===== ============================================= - Value Description - ===== ============================================= - 0 a regular polygon - 1 a star-like symbol - 2 an asterisk - 3 a circle (*numsides* and *angle* is ignored) - ===== ============================================= - - *angle*: - the angle of rotation of the symbol - - Finally, *marker* can be (*verts*, 0): *verts* is a - sequence of (*x*, *y*) vertices for a custom scatter - symbol. Alternatively, use the kwarg combination - *marker* = *None*, *verts* = *verts*. + %(MarkerTable)s Any or all of *x*, *y*, *s*, and *c* may be masked arrays, in which case all masks will be combined and only unmasked points diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index f799caddc5df..0dc8ac4ee8a7 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -736,19 +736,20 @@ def set_linestyle(self, linestyle): linestyle = 'None' self._linestyle = linestyle + @docstring.dedent_interpd def set_marker(self, marker): """ Set the line marker - %s + %(MarkerTable)s - %s - """ % (MarkerStyle.style_table, MarkerStyle.accepts) + %(MarkerAccepts)s + """ try: self._marker.set_marker(marker) except ValueError as e: verbose.report(str(e)) - + def set_markeredgecolor(self, ec): """ Set the marker edge color diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index b7ee99c8814a..4befa8dd5908 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -4,9 +4,12 @@ `~matplotlib.axes.Axes.scatter`. """ +import textwrap + import numpy as np from cbook import is_math_text, is_string_like, is_numlike, iterable +import docstring from matplotlib import rcParams from path import Path from transforms import IdentityTransform, Affine2D @@ -17,20 +20,43 @@ class MarkerStyle: style_table = """ -======================== ===================================================== -marker description -======================== ===================================================== +============================== =============================================== +marker description +============================== =============================================== %s -``'$...$'`` render the string using mathtext -(numsides, style, angle) see below -verts where verts is a list of (x, y) pairs in range (0, 1) -======================== ===================================================== - -TODO: Describe tuple form +``'$...$'`` render the string using mathtext +*verts* a list of (x, y) pairs in range (0, 1) +(*numsides*, *style*, *angle*) see below +============================== =============================================== + +The marker can also be a tuple (*numsides*, *style*, *angle*), which +will create a custom, regular symbol. + + *numsides*: + the number of sides + + *style*: + the style of the regular symbol: + + ===== ============================================= + Value Description + ===== ============================================= + 0 a regular polygon + 1 a star-like symbol + 2 an asterisk + 3 a circle (*numsides* and *angle* is ignored) + ===== ============================================= + + *angle*: + the angle of rotation of the symbol + +For backward compatibility, the form (*verts*, 0) is also accepted, +but it is equivalent to just *verts* for giving a raw set of vertices +that define the shape. """ # TODO: Automatically generate this - accepts = """ACCEPTS: [ %s | ``'$...$'`` | tuple ]""" + accepts = """ACCEPTS: [ %s | ``'$...$'`` | *tuple* | *Nx2 array* ]""" markers = { '.' : 'point', @@ -603,11 +629,14 @@ def _set_x(self): self._path = self._x_path _styles = [(repr(x), y) for x, y in MarkerStyle.markers.items()] -_styles.sort() +_styles.sort(lambda x, y: cmp(x[1], y[1])) MarkerStyle.style_table = ( MarkerStyle.style_table % - '\n'.join(['``%7s`` %33s' % (x, y) for (x, y) in _styles])) + '\n'.join(['%-30s %-33s' % ('``%s``' % x, y) for (x, y) in _styles])) -MarkerStyle.accepts = ( +MarkerStyle.accepts = textwrap.fill( MarkerStyle.accepts % ' | '.join(['``%s``' % x for (x, y) in _styles])) + +docstring.interpd.update(MarkerTable=MarkerStyle.style_table) +docstring.interpd.update(MarkerAccepts=MarkerStyle.accepts) From 00b029e538dd793d6acc71bcca83e9ff17eada2b Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 15 Jul 2011 16:21:50 -0400 Subject: [PATCH 043/214] Clarify CHANGELOG comment. --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index c2861a05fd63..fe936b9bfe8b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,7 +5,7 @@ scatter: "d" used to mean "diamond", it now means "narrow - diamond", now "D" can be used for a "diamond". + diamond". "D" can be used for a "diamond". 2011-07-10 Fixed argument handling error in tripcolor/triplot/tricontour, issue #203. - IMT From 85d3ea9a3ac5df4541901e4e69045133f6ce7b12 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 15 Jul 2011 16:22:12 -0400 Subject: [PATCH 044/214] No need to square just to take the square root. --- lib/matplotlib/markers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index 4befa8dd5908..7ec1319ee300 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -178,8 +178,7 @@ def _set_nothing(self): def _set_custom_marker(self, path): verts = path.vertices - rescale = np.sqrt(max(np.max(verts[:,0]**2), - np.max(verts[:,1]**2))) + rescale = max(np.max(np.abs(verts[:,0])), np.max(np.abs(verts[:,1])))) self._transform = Affine2D().scale(1.0 / rescale) self._path = path From af7ac12ef7a85350c27e3445ea93d43d882eac9c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 15 Jul 2011 16:34:54 -0400 Subject: [PATCH 045/214] Fix some regression tests. --- lib/matplotlib/markers.py | 6 +++--- .../test_axes/polar_wrap_360.png | Bin 59933 -> 59966 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index 7ec1319ee300..6b6612490a78 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -178,7 +178,7 @@ def _set_nothing(self): def _set_custom_marker(self, path): verts = path.vertices - rescale = max(np.max(np.abs(verts[:,0])), np.max(np.abs(verts[:,1])))) + rescale = max(np.max(np.abs(verts[:,0])), np.max(np.abs(verts[:,1]))) self._transform = Affine2D().scale(1.0 / rescale) self._path = path @@ -518,13 +518,13 @@ def _set_vline(self): self._transform = Affine2D().scale(0.5) self._snap_threshold = 1.0 self._filled = False - self._path = _line_marker_path + self._path = self._line_marker_path def _set_hline(self): self._transform = Affine2D().scale(0.5).rotate_deg(90) self._snap_threshold = 1.0 self._filled = False - self._path = _line_marker_path + self._path = self._line_marker_path _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) def _set_tickleft(self): diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.png index 419fc6980c2bb803e2503988419525ec76cb9136..d69380e09b7d7418def83bd0dc76e0ec4a5132da 100644 GIT binary patch delta 42283 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 J+St|q{{aOYDFXli delta 42312 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 From c9e0ebc6f284518c4b1b4e5e26b920f5a9fcf84e Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 18 Jul 2011 09:16:30 -0400 Subject: [PATCH 046/214] Fix typo in CHANGELOG and add attribution. --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index fe936b9bfe8b..72bf2d153f4c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -2001-07-15 The set of markers available in the plot() and scatter() +2011-07-15 The set of markers available in the plot() and scatter() commands has been unified. In general, this gives more options to both than were previously available, however, there is one backward-incompatible change to the markers in @@ -7,6 +7,8 @@ "d" used to mean "diamond", it now means "narrow diamond". "D" can be used for a "diamond". + -MGD + 2011-07-10 Fixed argument handling error in tripcolor/triplot/tricontour, issue #203. - IMT From d49ecc643378773ba72d0a97049ad79a9f3360da Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 18 Jul 2011 10:06:26 -0400 Subject: [PATCH 047/214] Fix upside down text problem in SVG when math and regular text are mixed. --- lib/matplotlib/backends/backend_svg.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 419528dbf8f8..9640f1f7ba91 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -447,7 +447,7 @@ def _write_svgfonts(self): glyph = font.load_char(char, flags=LOAD_NO_HINTING) verts, codes = font.get_path() path = Path(verts, codes) - path_data = self._convert_path(path, None) + path_data = self._convert_path(path) # name = font.get_glyph_name(char) writer.element( 'glyph', @@ -479,7 +479,7 @@ def option_image_nocomposite(self): """ return rcParams['svg.image_noscale'] - def _convert_path(self, path, transform, clip=None, simplify=None): + def _convert_path(self, path, transform=None, clip=None, simplify=None): if clip: clip = (0.0, 0.0, self.width, self.height) else: @@ -798,13 +798,11 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): y -= ((font.get_descent() / 64.0) * (prop.get_size_in_points() / text2path.FONT_SCALE)) - _flip = Affine2D().scale(1.0, -1.0) - if glyph_map_new: writer.start('defs') for char_id, glyph_path in glyph_map_new.iteritems(): path = Path(*glyph_path) - path_data = self._convert_path(path, _flip, simplify=False) + path_data = self._convert_path(path, simplify=False) writer.element('path', id=char_id, d=path_data) writer.end('defs') @@ -812,10 +810,11 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): attrib = {} attrib['style'] = generate_css(style) + font_scale = fontsize / text2path.FONT_SCALE attrib['transform'] = generate_transform([ ('translate', (x, y)), ('rotate', (-angle,)), - ('scale', (fontsize / text2path.FONT_SCALE,))]) + ('scale', (font_scale, -font_scale))]) writer.start('g', attrib=attrib) for glyph_id, xposition, yposition, scale in glyph_info: @@ -851,7 +850,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): path_data = "" else: path = Path(*glyph_path) - path_data = self._convert_path(path, None, simplify=False) + path_data = self._convert_path(path, simplify=False) writer.element('path', id=char_id, d=path_data) writer.end('defs') @@ -879,7 +878,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): for verts, codes in rects: path = Path(verts, codes) - path_data = self._convert_path(path, None, simplify=False) + path_data = self._convert_path(path, simplify=False) writer.element('path', d=path_data) writer.end('g') From 2656639d6ae02f85cc6ecf889cdccd49efd49727 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 18 Jul 2011 10:06:26 -0400 Subject: [PATCH 048/214] Fix upside down text problem in SVG when math and regular text are mixed. --- lib/matplotlib/backends/backend_svg.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 419528dbf8f8..44c84ee743a4 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -447,7 +447,7 @@ def _write_svgfonts(self): glyph = font.load_char(char, flags=LOAD_NO_HINTING) verts, codes = font.get_path() path = Path(verts, codes) - path_data = self._convert_path(path, None) + path_data = self._convert_path(path) # name = font.get_glyph_name(char) writer.element( 'glyph', @@ -479,7 +479,7 @@ def option_image_nocomposite(self): """ return rcParams['svg.image_noscale'] - def _convert_path(self, path, transform, clip=None, simplify=None): + def _convert_path(self, path, transform=None, clip=None, simplify=None): if clip: clip = (0.0, 0.0, self.width, self.height) else: @@ -798,13 +798,11 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): y -= ((font.get_descent() / 64.0) * (prop.get_size_in_points() / text2path.FONT_SCALE)) - _flip = Affine2D().scale(1.0, -1.0) - if glyph_map_new: writer.start('defs') for char_id, glyph_path in glyph_map_new.iteritems(): path = Path(*glyph_path) - path_data = self._convert_path(path, _flip, simplify=False) + path_data = self._convert_path(path, simplify=False) writer.element('path', id=char_id, d=path_data) writer.end('defs') @@ -812,10 +810,11 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): attrib = {} attrib['style'] = generate_css(style) + font_scale = fontsize / text2path.FONT_SCALE attrib['transform'] = generate_transform([ ('translate', (x, y)), ('rotate', (-angle,)), - ('scale', (fontsize / text2path.FONT_SCALE,))]) + ('scale', (font_scale, -font_scale))]) writer.start('g', attrib=attrib) for glyph_id, xposition, yposition, scale in glyph_info: @@ -851,19 +850,19 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): path_data = "" else: path = Path(*glyph_path) - path_data = self._convert_path(path, None, simplify=False) + path_data = self._convert_path(path, simplify=False) writer.element('path', id=char_id, d=path_data) writer.end('defs') glyph_map.update(glyph_map_new) attrib = {} + font_scale = fontsize / text2path.FONT_SCALE attrib['style'] = generate_css(style) attrib['transform'] = generate_transform([ ('translate', (x, y)), ('rotate', (-angle,)), - ('scale', (fontsize / text2path.FONT_SCALE, - -fontsize / text2path.FONT_SCALE))]) + ('scale', (font_scale, - font_scale))]) writer.start('g', attrib=attrib) for char_id, xposition, yposition, scale in glyph_info: @@ -879,7 +878,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): for verts, codes in rects: path = Path(verts, codes) - path_data = self._convert_path(path, None, simplify=False) + path_data = self._convert_path(path, simplify=False) writer.element('path', d=path_data) writer.end('g') From 2f8916c0733cbe71cdb84d8412bd0ac7db481a98 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Mon, 18 Jul 2011 10:31:28 -0500 Subject: [PATCH 049/214] Added a dummy get_tightbbox to Axis3D objects to allow bbox_inches='tight' to mostly work. Closes #393. --- lib/mpl_toolkits/mplot3d/axis3d.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/mpl_toolkits/mplot3d/axis3d.py b/lib/mpl_toolkits/mplot3d/axis3d.py index 368f72bfa030..faa1c260de5a 100644 --- a/lib/mpl_toolkits/mplot3d/axis3d.py +++ b/lib/mpl_toolkits/mplot3d/axis3d.py @@ -405,6 +405,13 @@ def set_view_interval(self, vmin, vmax, ignore=False): Vmin, Vmax = self.get_view_interval() self.v_interval = min(vmin, Vmin), max(vmax, Vmax) + # TODO: Get this to work properly when mplot3d supports + # the transforms framework. + def get_tightbbox(self, renderer) : + # Currently returns None so that Axis.get_tightbbox + # doesn't return junk info. + return None + # Use classes to look at different data limits class XAxis(Axis): From 4ad07656e72a2e9219f1c638007cee667c86fb2d Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 18 Jul 2011 14:15:27 -0400 Subject: [PATCH 050/214] Add a "radius" to point_in_path to prevent floating-point rounding error from making annotations disappear. --- lib/matplotlib/axes.py | 2 +- lib/matplotlib/patches.py | 14 ++++++++------ lib/matplotlib/path.py | 5 +++-- setupext.py | 1 + src/_path.cpp | 21 +++++++++++++-------- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index c6dd94a9c47e..11b64512adb7 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -3001,7 +3001,7 @@ def contains_point(self, point): required. """ - return self.patch.contains_point(point) + return self.patch.contains_point(point, radius=1.0) def pick(self, *args): """ diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index b6d8bdf4d1c3..0771ff227a0c 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -112,7 +112,7 @@ def get_verts(self): return polygons[0] return [] - def contains(self, mouseevent): + def contains(self, mouseevent, radius=None): """Test whether the mouse event occurred in the patch. Returns T/F, {} @@ -122,18 +122,20 @@ def contains(self, mouseevent): # algebraic solution to hit-testing should override this # method. if callable(self._contains): return self._contains(self,mouseevent) - + if radius is None: + radius = self.get_linewidth() inside = self.get_path().contains_point( - (mouseevent.x, mouseevent.y), self.get_transform()) + (mouseevent.x, mouseevent.y), self.get_transform(), radius) return inside, {} - def contains_point(self, point): + def contains_point(self, point, radius=None): """ Returns *True* if the given point is inside the path (transformed with its transform attribute). """ - return self.get_path().contains_point(point, - self.get_transform()) + if radius is None: + radius = self.get_linewidth() + return self.get_path().contains_point(point, self.get_transform(), radius) def update_from(self, other): """ diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index da37d7d72699..82f20c449a56 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -265,7 +265,7 @@ def transformed(self, transform): return Path(transform.transform(self.vertices), self.codes, self._interpolation_steps) - def contains_point(self, point, transform=None): + def contains_point(self, point, transform=None, radius=0.0): """ Returns *True* if the path contains the given point. @@ -274,7 +274,8 @@ def contains_point(self, point, transform=None): """ if transform is not None: transform = transform.frozen() - return point_in_path(point[0], point[1], self, transform) + result = point_in_path(point[0], point[1], radius, self, transform) + return result def contains_path(self, path, transform=None): """ diff --git a/setupext.py b/setupext.py index fc84c4d3c6b0..962cedc3d752 100644 --- a/setupext.py +++ b/setupext.py @@ -1192,6 +1192,7 @@ def build_path(ext_modules, packages): if BUILT_PATH: return # only build it if you you haven't already agg = ( + 'agg_vcgen_contour.cpp', 'agg_curves.cpp', 'agg_bezier_arc.cpp', 'agg_trans_affine.cpp', diff --git a/src/_path.cpp b/src/_path.cpp index e99636ce06bd..12870b3c4bd5 100644 --- a/src/_path.cpp +++ b/src/_path.cpp @@ -9,6 +9,7 @@ #include "CXX/Extensions.hxx" +#include "agg_conv_contour.h" #include "agg_conv_curve.h" #include "agg_conv_stroke.h" #include "agg_conv_transform.h" @@ -225,12 +226,13 @@ point_in_path_impl(const double tx, const double ty, T& path) } inline bool -point_in_path(double x, double y, PathIterator& path, +point_in_path(double x, double y, double r, PathIterator& path, const agg::trans_affine& trans) { typedef agg::conv_transform transformed_path_t; typedef PathNanRemover no_nans_t; typedef agg::conv_curve curve_t; + typedef agg::conv_contour contour_t; if (path.total_vertices() < 3) { @@ -240,7 +242,9 @@ point_in_path(double x, double y, PathIterator& path, transformed_path_t trans_path(path, trans); no_nans_t no_nans_path(trans_path, true, path.has_curves()); curve_t curved_path(no_nans_path); - return point_in_path_impl(x, y, curved_path); + contour_t contoured_path(curved_path); + contoured_path.width(fabs(r)); + return point_in_path_impl(x, y, contoured_path); } inline bool @@ -263,14 +267,15 @@ point_on_path(double x, double y, double r, PathIterator& path, Py::Object _path_module::point_in_path(const Py::Tuple& args) { - args.verify_length(4); + args.verify_length(5); double x = Py::Float(args[0]); double y = Py::Float(args[1]); - PathIterator path(args[2]); - agg::trans_affine trans = py_to_agg_transformation_matrix(args[3].ptr(), false); + double r = Py::Float(args[2]); + PathIterator path(args[3]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[4].ptr(), false); - if (::point_in_path(x, y, path, trans)) + if (::point_in_path(x, y, r, path, trans)) { return Py::Int(1); } @@ -664,7 +669,7 @@ _path_module::point_in_path_collection(const Py::Tuple& args) if (filled) { - if (::point_in_path(x, y, path, trans)) + if (::point_in_path(x, y, radius, path, trans)) result.append(Py::Int((int)i)); } else @@ -696,7 +701,7 @@ path_in_path(PathIterator& a, const agg::trans_affine& atrans, b_curved.rewind(0); while (b_curved.vertex(&x, &y) != agg::path_cmd_stop) { - if (!::point_in_path(x, y, a, atrans)) + if (!::point_in_path(x, y, 0.0, a, atrans)) return false; } From ec035b45f5bc1c4b881f181eaef47922f3aa45c6 Mon Sep 17 00:00:00 2001 From: Darren Dale Date: Mon, 18 Jul 2011 15:27:17 -0400 Subject: [PATCH 051/214] failure to set PyQt4 API v2 defaults to v1 with helpful feedback --- lib/matplotlib/backends/qt4_compat.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/qt4_compat.py b/lib/matplotlib/backends/qt4_compat.py index 220ef1bb4917..7622ca82f38d 100644 --- a/lib/matplotlib/backends/qt4_compat.py +++ b/lib/matplotlib/backends/qt4_compat.py @@ -2,8 +2,7 @@ """ import os -import warnings -from matplotlib import rcParams +from matplotlib import rcParams, verbose # Available APIs. QT_API_PYQT = 'PyQt4' # API is not set here; Python 2.x default is V 1 @@ -36,8 +35,23 @@ if QT_API in (QT_API_PYQT, QT_API_PYQTv2): import sip if QT_API == QT_API_PYQTv2: - sip.setapi('QString', 2) - sip.setapi('QVariant', 2) + if QT_API_ENV == 'pyqt': + cond = ("Found 'QT_API=pyqt' environment variable. " + "Setting PyQt4 API accordingly.\n") + else: + cond = "PyQt API v2 specified." + try: + sip.setapi('QString', 2) + except: + res = 'QString API v2 specification failed. Defaulting to v1.' + verbose.report(cond+res, 'helpful') + # condition has now been reported, no need to repeat it: + cond = "" + try: + sip.setapi('QVariant', 2) + except: + res = 'QVariant API v2 specification failed. Defaulting to v1.' + verbose.report(cond+res, 'helpful') from PyQt4 import QtCore, QtGui From 7352a1d9999fc4873da073de2d87315e9577888b Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Wed, 20 Jul 2011 22:57:36 +0900 Subject: [PATCH 052/214] Fixes an error message in legend creation when numpoints <= 0 (reproted by to Steve Ward) --- lib/matplotlib/legend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 9a70e8df3ab5..2be13686ab68 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -278,7 +278,7 @@ def __init__(self, parent, handles, labels, self._ncol = ncol if self.numpoints <= 0: - raise ValueError("numpoints must be >= 0; it was %d"% numpoints) + raise ValueError("numpoints must be > 0; it was %d"% numpoints) # introduce y-offset for handles of the scatter plot if scatteryoffsets is None: From 6a982b49bdf09409e322bd99afaf4adf1645fd62 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Thu, 21 Jul 2011 01:00:51 +0900 Subject: [PATCH 053/214] slight improvement on demo_floating_axes.py --- examples/axes_grid/demo_floating_axes.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/axes_grid/demo_floating_axes.py b/examples/axes_grid/demo_floating_axes.py index e6712ac01363..4ffb9ead058d 100644 --- a/examples/axes_grid/demo_floating_axes.py +++ b/examples/axes_grid/demo_floating_axes.py @@ -19,10 +19,12 @@ def setup_axes1(fig, rect): ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper) fig.add_subplot(ax1) + aux_ax = ax1.get_aux_axes(tr) + grid_helper.grid_finder.grid_locator1._nbins = 4 grid_helper.grid_finder.grid_locator2._nbins = 4 - return ax1 + return ax1, aux_ax def setup_axes2(fig, rect): @@ -130,8 +132,9 @@ def setup_axes3(fig, rect): fig = plt.figure(1, figsize=(8, 4)) fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95) - ax1 = setup_axes1(fig, 131) - + ax1, aux_ax2 = setup_axes1(fig, 131) + aux_ax2.bar([0, 1, 2, 3], [3, 2, 1, 3]) + #theta = np.random.rand(10) #*.5*np.pi #radius = np.random.rand(10) #+1. #aux_ax1.scatter(theta, radius) From 67b1cd650f574f9c53ce3fbe0227743ee48ea15d Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Fri, 22 Jul 2011 10:34:31 +0900 Subject: [PATCH 054/214] textpath.py : delay _get_adobe_standard_encoding call until needed. Closes #405 --- lib/matplotlib/textpath.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index cc07157150e9..5865dcda408d 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -34,7 +34,7 @@ def __init__(self): self._texmanager = None - self._adobe_standard_encoding = self._get_adobe_standard_encoding() + self._adobe_standard_encoding = None def _get_adobe_standard_encoding(self): @@ -287,6 +287,9 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, if self.tex_font_map is None: self.tex_font_map = dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + if self._adobe_standard_encoding is None: + self._adobe_standard_encoding = self._get_adobe_standard_encoding() + fontsize = prop.get_size_in_points() if hasattr(texmanager, "get_dvi"): # dvifilelike = texmanager.get_dvi(s, self.FONT_SCALE) From 0e6a2b6e1e79e8bc2e3aba1a956c4a4b995ad211 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 13 Jul 2011 14:28:52 -0400 Subject: [PATCH 055/214] Change how symlog works to avoid numerical problems, particular when linthresh <= 1.0. This changes the appearance of symlog plots hopefully for the for the better. Closes #396 --- CHANGELOG | 3 + lib/matplotlib/scale.py | 41 +- .../baseline_images/test_axes/symlog.pdf | Bin 8530 -> 7255 bytes .../baseline_images/test_axes/symlog.png | Bin 18330 -> 20495 bytes .../baseline_images/test_axes/symlog.svg | 3060 ++++--- .../baseline_images/test_axes/symlog2.pdf | Bin 0 -> 14405 bytes .../baseline_images/test_axes/symlog2.png | Bin 0 -> 57010 bytes .../baseline_images/test_axes/symlog2.svg | 7371 +++++++++++++++++ lib/matplotlib/tests/test_axes.py | 37 + lib/matplotlib/ticker.py | 35 +- 10 files changed, 9420 insertions(+), 1127 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_axes/symlog2.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_axes/symlog2.png create mode 100644 lib/matplotlib/tests/baseline_images/test_axes/symlog2.svg diff --git a/CHANGELOG b/CHANGELOG index 72bf2d153f4c..a46c6bdf3a53 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,9 @@ diamond". "D" can be used for a "diamond". -MGD +2011-07-13 Fix numerical problems in symlog scale, particularly when + linthresh <= 1.0. Symlog plots may look different if one + was depending on the old broken behavior - MGD 2011-07-10 Fixed argument handling error in tripcolor/triplot/tricontour, issue #203. - IMT diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index b5fd1cc3cb7c..c8f816eeab97 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -321,25 +321,23 @@ def __init__(self, base, linthresh): self.base = base self.linthresh = abs(linthresh) self._log_base = np.log(base) - self._logb_linthresh = np.log(linthresh) / self._log_base - self._logb_minlog = np.floor(self._logb_linthresh - 1e-10) - self._linadjust = np.abs((np.log(linthresh) - self._logb_minlog) / - linthresh) + logb_linthresh = np.log(linthresh) / self._log_base + self._linadjust = 1.0 - logb_linthresh + self._linscale = 1.0 / linthresh def transform(self, a): a = np.asarray(a) sign = np.sign(a) masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) - log = sign * (ma.log(np.abs(masked)) / self._log_base - self._logb_minlog) if masked.mask.any(): - return np.asarray(ma.where(masked.mask, - a * self._linadjust, - log)) + log = sign * (ma.log(np.abs(masked)) / self._log_base + self._linadjust) + return np.asarray(ma.where(masked.mask, a * self._linscale, log)) else: - return np.asarray(log) + return sign * (np.log(np.abs(a)) / self._log_base + self._linadjust) def inverted(self): - return SymmetricalLogScale.InvertedSymmetricalLogTransform(self.base, self.linthresh) + return SymmetricalLogScale.InvertedSymmetricalLogTransform( + self.base, self.linthresh) class InvertedSymmetricalLogTransform(Transform): input_dims = 1 @@ -350,20 +348,22 @@ def __init__(self, base, linthresh): Transform.__init__(self) self.base = base self.linthresh = linthresh - self._log_base = np.log(base) - self._log_linthresh = np.log(linthresh) / self._log_base - self._linadjust = linthresh / (np.log(linthresh) / self._log_base) + log_base = np.log(base) + logb_linthresh = np.log(linthresh) / log_base + self._linadjust = 1.0 - logb_linthresh def transform(self, a): a = np.asarray(a) - return np.where(a <= self._log_linthresh, - np.where(a >= -self._log_linthresh, - a * self._linadjust, - -(np.power(self.base, -a))), - np.power(self.base, a)) + sign = np.sign(a) + masked = ma.masked_inside(a, -1.0, 1.0, copy=False) + result = np.where((a >= -1.0) & (a <= 1.0), + a * self.linthresh, + sign * np.power(self.base, np.abs(a - sign * self._linadjust))) + return result def inverted(self): - return SymmetricalLogScale.SymmetricalLogTransform(self.base) + return SymmetricalLogScale.SymmetricalLogTransform( + self.base, self.linthresh) def __init__(self, axis, **kwargs): """ @@ -393,6 +393,9 @@ def __init__(self, axis, **kwargs): self._transform = self.SymmetricalLogTransform(base, linthresh) + assert base > 0.0 + assert linthresh > 0.0 + self.base = base self.linthresh = linthresh self.subs = subs diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf b/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf index 822c5cdfb03fbe4413ee03b9db3b2e581a02bcbe..acb01e37ad2d651257bc1340ecd3d7aeeb4bced5 100644 GIT binary patch delta 2723 zcmZWoc_5VQ8aMVvp+hr5eh%a|0Ytqrd zL8VNV6lt-aBX!%TsL{d|Dq3)7ES*z*|9sE$d!P4xf6wptyuFV9wK*RPe_A2LS`abvY^y8HY5EUk2vGKa1U2H|?( zuZ+i2_G1&3>RvY-+2M028BdQ{Dx)oW?!sd`Lo>}Ho`Peycew>PIuK8$tN@*k zT&Eo#!A>B7E8DzFgMjIoXeW|oovEGTtbq>5IUeP&$xu(prjPjmn{&Y;d+|v=YqK{*GwT1g`9L_kl2QqB4$uN4$ zo!(9RH*dRBV%9oc?ohtK;F@upg-dpt8>>2ZQ{L0ljlD0ui48M3*;%h+Ur;b{ zvvK8L)a1OzQd*2fW=8_mHc+Emf8)z9jry@iM3tFJ5A3GOW&|ct3UaSnq9a(hD%=?Z zwS9s62jpJ#<|^Kfc{M(gtyZ%2`aNVRhZ&q-ndBa~A*d&{;!K?qf2#MsM?xR{uaXBj zO=atvQ5E8Uv)e;Pll` z^z><$D29wGs#>SyQpsqx|FHsGc1orrV>%38>3^u&m)>a6XXP4L%yL_`_xbi$?N5=9 z5N2>*SA%u`J@X1L|BL-=&08+_@|!Y}zkaINdG0HtbfTf{6Thy^w%_ArNM%T6HEq+g zOw&{?%vmPg-K|o_l6RCbO%t1)KOC_2`N?SEun-%_5t5toxE44>s(^beye8>pK9v`Y~&*%Hf&2~r&MBGW_0M1cz z(Vf<$0d7;2h_pm}aC@uM z7Fb38i$%nmr691|Gq_5*P0RZB!u|b0x|=vs1S(-| z*!8D`7XvsP$*7e$q0VwSaMQ{H%A?3#Aev_#7L29od5Z@Om*#6Kb=#=N#$db2dj6${ zt?!*o<@CflO?hq6RqbomB&bhn-lfTdnpy|7MJ0^SVAmP1cf3rmV*EWVC>!t2W_w< z$W9T2R;yBEL2KyQFD4raSis&M&SEpEq5I&Rd>j$ygV~0;;Df;uw_}KS+1(l`nod@y zm5=6hC}?!RYBrQJubggY?UMX@WnM2^ab0=?%tm@v&2OqZVX`1;KDJP2!C;vA@Yc%J zFlc;*DWs$k2PLSQLS-70kes?{O{=CB3@Th{3dtk(L%m97PyvDtIVhVzmPi+EINCX! zMx!#RQ4}f*2n6s108Quar&FV#WMn8bsf>U=A)8^?ng%T$c|J&3?9tX1K(nX^s8Ik& zlt5lfn*h*yA!UVg0MKS3X2&uBEM_sLGpSSnBuO(kn#PD>0$8bVk`v;nOi3MfA)$pI zpaNLjLc)lW#CQOsBPo-}NR8Sf)mgeI{Y$xQ2BF9`B`^Y{jzXz`7;6v*;s`bbJVZj7 zYn#E*P7>kS3?^W@FO72525o*i4~xZ1 zH2r=r7H1>H_!9JQ_E-W&qTLULHl&|091bI~_xm~=5&IKqoVAU_*zfD`63PF@*3YkE z@Ho;xzy*v*_~#{TW@vaMl{s(WzoKXo`w0-BkJOP|I{#cknQRV|N`n)L1R~tXXp`q= G`2PWHlX?39 delta 3783 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

J}s0%`eDOMayePq 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 literal 18330 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 - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog2.pdf b/lib/matplotlib/tests/baseline_images/test_axes/symlog2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d4ebdd05f3a164a51806df78245d890f6bf040c2 GIT binary patch literal 14405 zcmb`u2{=_>7ckyHGMAaeEkk6u^Sx$8Ny%K1`NlP7zUC>EYnIFkNv1@~Jd-K25S5wC zQ$j@e&XI;+@9+Qq-{*TiJ-dC*K5MVNroGl)tj(ixK~4xRjH2LqJ^;xorGP_V5bIm! z6cQ2;=rtD`JOnC>Bj9dZn?Rr{I1{`*1OWi3L8PQ8@K#13pvWH+G?j0e;|&QA>>dm- zfk439SwYa?D+N@=&e~8NPk?9xs4mC>=<&`32=uZgfL3O|m)-9#Lv$g~i_U~g>I57C z4?+Dvpl*sYGP5#)V1A&Nv$i5YkbBR+$$`Uwfu9V>0uXpBf;~j^$BZ8gfqX!qYIu8V z2RlQ6Baj0%kUcv9_6L6yP({3v8BWI98K4%#h{j?dC?o - + - - + - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - + - + - + + - - + + - - + - + + - + + - - + + - - + - - - - - - - - - + - - + - - - + + - + - - - - - - - - - - - - - - - - - + + + + + + + + - + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - + - - - - - - - - - - - - - - - - - + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - + - - - - - - - - - - - - - - - - - + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + - + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + - - - - - - - - + - + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

-SP1(w{5IncW6hg+S$Q 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 + + + diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 6aa76d5b210e..df32acfcc10e 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -468,6 +468,43 @@ def test_symlog(): ax.set_xscale=('linear') ax.set_ylim(-1,10000000) +@image_comparison(baseline_images=['symlog2']) +def test_symlog2(): + # Numbers from -50 to 50, with 0.1 as step + x = np.arange(-50,50, 0.001) + + fig = plt.figure() + ax = fig.add_subplot(511) + # Plots a simple linear function 'f(x) = x' + ax.plot(x, x) + ax.set_xscale('symlog', linthreshx=20.0) + ax.grid(True) + + ax = fig.add_subplot(512) + # Plots a simple linear function 'f(x) = x' + ax.plot(x, x) + ax.set_xscale('symlog', linthreshx=2.0) + ax.grid(True) + + ax = fig.add_subplot(513) + # Plots a simple linear function 'f(x) = x' + ax.plot(x, x) + ax.set_xscale('symlog', linthreshx=1.0) + ax.grid(True) + + ax = fig.add_subplot(514) + # Plots a simple linear function 'f(x) = x' + ax.plot(x, x) + ax.set_xscale('symlog', linthreshx=0.1) + ax.grid(True) + + ax = fig.add_subplot(515) + # Plots a simple linear function 'f(x) = x' + ax.plot(x, x) + ax.set_xscale('symlog', linthreshx=0.01) + ax.grid(True) + ax.set_ylim(-0.1, 0.1) + @image_comparison(baseline_images=['pcolormesh'], tol=0.02) def test_pcolormesh(): n = 12 diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 534569c8e07d..34b4d4e6ff38 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -1344,32 +1344,49 @@ def _set_numticks(self): def __call__(self): 'Return the locations of the ticks' b = self._transform.base + t = self._transform.linthresh vmin, vmax = self.axis.get_view_interval() vmin, vmax = self._transform.transform((vmin, vmax)) if vmax + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10: subs = np.array([1.0]) - elif numdec>6: subs = np.arange(2.0, b, 2.0) - else: subs = np.arange(2.0, b) + lt = np.log(t) / np.log(b) + + if vmin < 0: + if vmax < 0: + numdec = vmax - vmin + 1 + else: + numdec = (-vmin - lt + 1) + 1 + (vmax - lt + 1) else: - subs = np.asarray(self._subs) + numdec = vmax - vmin + 1 stride = 1 while numdec/stride+1 > self.numticks: stride += 1 - decades = np.arange(math.floor(vmin), math.ceil(vmax)+stride, stride) + if self._subs is None: + subs = np.arange(2.0, b) + else: + subs = np.asarray(self._subs) + + if vmin < 0: + if vmax < 0: + decades = -(b ** np.arange(vmin, vmax + 1, stride)) + else: + decades = np.asarray(list(-(b ** np.arange(np.floor(lt), np.ceil(-vmin) + stride, stride))[::-1]) + + [0] + + list(b ** np.arange(np.floor(lt), np.ceil(vmax) + stride, stride))) + else: + decades = b ** np.arange(vmin, vmax + 1, stride) + if len(subs) > 1 or subs[0] != 1.0: ticklocs = [] for decade in decades: - ticklocs.extend(subs * (np.sign(decade) * b ** np.abs(decade))) + ticklocs.extend(subs * decade) else: - ticklocs = np.sign(decades) * b ** np.abs(decades) + ticklocs = decades return self.raise_if_exceeds(np.array(ticklocs)) def view_limits(self, vmin, vmax): From 2655fdef732fb16e5027a64966e04e2c2a693584 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Tue, 26 Jul 2011 13:02:14 +0200 Subject: [PATCH 056/214] Silence divide by zero warning from np.log(0) in test. Inspired by how scipy tests does. --- lib/matplotlib/tests/test_axes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index df32acfcc10e..4bc58694416f 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -374,7 +374,11 @@ def test_hexbin_extent(): @image_comparison(baseline_images=['nonfinite_limits']) def test_nonfinite_limits(): x = np.arange(0., np.e, 0.01) - y = np.log(x) + olderr = np.seterr(divide='ignore') #silence divide by zero warning from log(0) + try: + y = np.log(x) + finally: + np.seterr(**olderr) x[len(x)/2] = np.nan fig = plt.figure() ax = fig.add_subplot(111) From 4f921b393c6f0de1520bf10d3dbe253445f46ad2 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Tue, 26 Jul 2011 20:20:48 +0200 Subject: [PATCH 057/214] filter left==right warning --- lib/matplotlib/tests/test_dates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index 43854ea4a6ab..44cfe3f7fe1e 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -3,6 +3,7 @@ from matplotlib.testing.decorators import image_comparison, knownfailureif, cleanup import matplotlib.pyplot as plt from nose.tools import assert_raises +import warnings @image_comparison(baseline_images=['date_empty']) def test_date_empty(): @@ -68,6 +69,7 @@ def test_too_many_date_ticks(): # setting equal datetimes triggers and expander call in # transforms.nonsingular which results in too many ticks in the # DayLocator. This should trigger a Locator.MAXTICKS RuntimeError + warnings.filterwarnings('ignore','Attempting to set identical left==right results\\nin singular transformations; automatically expanding.\\nleft=\d*\.\d*, right=\d*\.\d*',UserWarning,module='matplotlib.axes') t0 = datetime.datetime(2000, 1, 20) tf = datetime.datetime(2000, 1, 20) fig = plt.figure() From 7b3fa229a33a916c2ace7b9217e5ca123074341e Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Tue, 26 Jul 2011 20:21:34 +0200 Subject: [PATCH 058/214] filter font family Foo warning --- lib/matplotlib/tests/test_text.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index e01c23c897a0..bba84e6b619a 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -2,12 +2,12 @@ import matplotlib from matplotlib.testing.decorators import image_comparison, knownfailureif import matplotlib.pyplot as plt - +import warnings @image_comparison(baseline_images=['font_styles']) def test_font_styles(): from matplotlib.font_manager import FontProperties - + warnings.filterwarnings('ignore','findfont: Font family \[\'Foo\'\] not found. Falling back to .',UserWarning,module='matplotlib.font_manager') fig = plt.figure() ax = plt.subplot( 1, 1, 1 ) From e5e33692d1187574a249c6f2441e550d59220c9c Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Thu, 21 Jul 2011 01:04:16 +0900 Subject: [PATCH 059/214] implement handleheight parameter for legend. This addresses #327 --- lib/matplotlib/legend.py | 10 ++++++---- lib/matplotlib/legend_handler.py | 2 +- lib/matplotlib/rcsetup.py | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 9cab5cba5b7c..663b6a7d94ac 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -146,6 +146,7 @@ def __init__(self, parent, handles, labels, borderpad = None, # the whitespace inside the legend border labelspacing=None, #the vertical space between the legend entries handlelength=None, # the length of the legend handles + handleheight=None, # the height of the legend handles handletextpad=None, # the pad between the legend handle and text borderaxespad=None, # the pad between the axes and legend border columnspacing=None, # spacing between columns @@ -184,6 +185,7 @@ def __init__(self, parent, handles, labels, borderpad the fractional whitespace inside the legend border labelspacing the vertical space between the legend entries handlelength the length of the legend handles + handleheight the length of the legend handles handletextpad the pad between the legend handle and text borderaxespad the pad between the axes and legend border columnspacing the spacing between columns @@ -223,7 +225,7 @@ def __init__(self, parent, handles, labels, self._fontsize = self.prop.get_size_in_points() propnames=['numpoints', 'markerscale', 'shadow', "columnspacing", - "scatterpoints"] + "scatterpoints", "handleheight"] self.texts = [] self.legendHandles = [] @@ -585,9 +587,9 @@ def _init_legend_box(self, handles, labels): # The approximate height and descent of text. These values are # only used for plotting the legend handle. - height = self._approx_text_height() * 0.7 - descent = 0. - + descent = 0.35*self._approx_text_height()*(self.handleheight - 0.7) + # 0.35 and 0.7 are just heuristic numbers. this may need to be improbed + height = self._approx_text_height() * self.handleheight - descent # each handle needs to be drawn inside a box of (x, y, w, h) = # (0, -descent, width, height). And their corrdinates should # be given in the display coordinates. diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index baa3251b1045..e814e844097c 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -231,7 +231,7 @@ def _create_patch(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize): if self._patch_func is None: p = Rectangle(xy=(-xdescent, -ydescent), - width = width+xdescent, height=(height+ydescent)) + width = width, height=height) else: p = self._patch_func(legend=legend, orig_handle=orig_handle, xdescent=xdescent, ydescent=ydescent, diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 3c0095acf034..442517df6400 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -472,6 +472,7 @@ def __call__(self, s): 'legend.borderpad' : [0.4, validate_float], # units are fontsize 'legend.labelspacing' : [0.5, validate_float], # the vertical space between the legend entries 'legend.handlelength' : [2., validate_float], # the length of the legend lines + 'legend.handleheight' : [0.7, validate_float], # the length of the legend lines 'legend.handletextpad' : [.8, validate_float], # the space between the legend line and legend text 'legend.borderaxespad' : [0.5, validate_float], # the border between the axes and legend edge 'legend.columnspacing' : [2., validate_float], # the border between the axes and legend edge From fc27e71deebed2705356dce4900ae319fc7214ef Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Thu, 21 Jul 2011 01:04:45 +0900 Subject: [PATCH 060/214] update legend related items in matplotlibrc.template --- matplotlibrc.template | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/matplotlibrc.template b/matplotlibrc.template index 03f31910baaf..940e0dc23278 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -256,10 +256,16 @@ backend : %(backend)s #legend.borderpad : 0.5 # border whitspace in fontsize units #legend.markerscale : 1.0 # the relative size of legend markers vs. original # the following dimensions are in axes coords -#legend.labelsep : 0.010 # the vertical space between the legend entries -#legend.handlelen : 0.05 # the length of the legend lines -#legend.handletextsep : 0.02 # the space between the legend line and legend text -#legend.axespad : 0.02 # the border between the axes and legend edge +#legend.labelsep : 0.010 # deprecated; the vertical space between the legend entries +#legend.labelspacing : 0.5 # the vertical space between the legend entries in fraction of fontsize +#legend.handlelen : 0.05 # deprecated; the length of the legend lines +#legend.handlelength : 2. # the length of the legend lines in fraction of fontsize +#legend.handleheight : 0.7 # the height of the legend handle in fraction of fontsize +#legend.handletextsep : 0.02 # deprecated; the space between the legend line and legend text +#legend.handletextpad : 0.8 # the space between the legend line and legend text in fraction of fontsize +#legend.axespad : 0.02 # deprecated; the border between the axes and legend edge +#legend.borderaxespad : 0.5 # the border between the axes and legend edge in fraction of fontsize +#legend.columnspacing : 2. # the border between the axes and legend edge in fraction of fontsize #legend.shadow : False #legend.frameon : True # whether or not to draw a frame around legend From fc52ce5513b158c21b011702041ddad0ba5382fe Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Thu, 28 Jul 2011 15:04:17 +0900 Subject: [PATCH 061/214] update Axes.arrow documentation. Closes #141 --- lib/matplotlib/axes.py | 1 + lib/matplotlib/patches.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f7416c79ba15..f2a02b22f18d 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -6253,6 +6253,7 @@ def arrow(self, x, y, dx, dy, **kwargs): *y* + *dy*). Optional kwargs control the arrow properties: + %(FancyArrow)s **Example:** diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 0771ff227a0c..36593d7a95bf 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -981,6 +981,8 @@ def __init__(self, x, y, dx, dy, width=0.001, length_includes_head=False, \ Polygon.__init__(self, map(tuple, verts), **kwargs) +docstring.interpd.update({"FancyArrow":FancyArrow.__init__.__doc__}) + class YAArrow(Patch): """ Yet another arrow class. From 3f8e94f63beafc291af85d60039504839b68b1c2 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 28 Jul 2011 09:48:22 -0400 Subject: [PATCH 062/214] Fix how font property hash is computed so it properly takes into account the font size. Closes #406. --- lib/matplotlib/font_manager.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 49f7674f8d38..25296cc82445 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -680,8 +680,14 @@ def _parse_fontconfig_pattern(self, pattern): return parse_fontconfig_pattern(pattern) def __hash__(self): - l = [(k, getattr(self, "get" + k)()) for k in sorted(self.__dict__)] - return hash(repr(l)) + l = (tuple(self.get_family()), + self.get_slant(), + self.get_variant(), + self.get_weight(), + self.get_stretch(), + self.get_size_in_points(), + self.get_file()) + return hash(l) def __str__(self): return self.get_fontconfig_pattern() From d151a2ab082d6ddccb9014b33301d21d5933825b Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 29 Jul 2011 11:33:19 +0200 Subject: [PATCH 063/214] reset warnings in the teardown_class --- lib/matplotlib/testing/decorators.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/testing/decorators.py b/lib/matplotlib/testing/decorators.py index cae9218804d2..54fc958c79a6 100644 --- a/lib/matplotlib/testing/decorators.py +++ b/lib/matplotlib/testing/decorators.py @@ -8,6 +8,7 @@ from matplotlib import pyplot as plt import numpy as np from matplotlib.testing.compare import comparable_formats, compare_images +import warnings def knownfailureif(fail_condition, msg=None, known_exception_class=None ): """ @@ -61,7 +62,8 @@ def teardown_class(cls): matplotlib.units.registry.clear() matplotlib.units.registry.update(cls.original_units_registry) - + warnings.resetwarnings() #reset any warning filters set in tests + def test(self): self._func() From 8f7f69a2a78b94446649709e8b8cd18f2b2db11c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 29 Jul 2011 11:05:19 -0400 Subject: [PATCH 064/214] Adds an rcParam "axes.formatter.use_locale", that when true will use the current locale to format tick labels. For example, in the fr_FR locale, the ',' will be used as a decimal separator. --- CHANGELOG | 5 +++++ lib/matplotlib/__init__.py | 4 +++- lib/matplotlib/axes.py | 13 +++++++++++ lib/matplotlib/rcsetup.py | 1 + lib/matplotlib/ticker.py | 44 ++++++++++++++++++++++++++++++++------ matplotlibrc.template | 2 ++ 6 files changed, 62 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a46c6bdf3a53..47d2eac4ee9a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2011-07-29 A new rcParam "axes.formatter.use_locale" was added, that, + when True, will use the current locale to formatter tick + labels. This means that, for example, in the fr_FR locale, + ',' will be used as a decimal separator. - MGD + 2011-07-15 The set of markers available in the plot() and scatter() commands has been unified. In general, this gives more options to both than were previously available, however, diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 92ff3e4ac02d..a29f6b9ec078 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -786,7 +786,9 @@ def rc_params(fail_on_error=False): rcParams['ps.usedistiller'] = checkdep_ps_distiller(rcParams['ps.usedistiller']) rcParams['text.usetex'] = checkdep_usetex(rcParams['text.usetex']) - +if rcParams['axes.formatter.use_locale']: + import locale + locale.setlocale(locale.LC_ALL, '') def rc(group, **kwargs): """ diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f2a02b22f18d..9dcc9c013b4c 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2108,6 +2108,13 @@ def ticklabel_format(self, **kwargs): numeric offset is specified, it will be used. *axis* [ 'x' | 'y' | 'both' ] + *useLocale* If True, format the number according to + the current locale. The affects things + such as the character used for the + decimal separator. If False, use + C-style (English) formatting. The + default setting is controlled by the + axes.formatter.use_locale rcparam. ============ ========================================= Only the major ticks are affected. @@ -2120,6 +2127,7 @@ def ticklabel_format(self, **kwargs): style = kwargs.pop('style', '').lower() scilimits = kwargs.pop('scilimits', None) useOffset = kwargs.pop('useOffset', None) + use_locale = kwargs.pop('useLocale', None) axis = kwargs.pop('axis', 'both').lower() if scilimits is not None: try: @@ -2156,6 +2164,11 @@ def ticklabel_format(self, **kwargs): self.xaxis.major.formatter.set_useOffset(useOffset) if axis == 'both' or axis == 'y': self.yaxis.major.formatter.set_useOffset(useOffset) + if useLocale is not None: + if axis == 'both' or axis == 'x': + self.xaxis.major.formatter.set_useLocale(useLocale) + if axis == 'both' or axis == 'y': + self.yaxis.major.formatter.set_useLocale(useLocale) except AttributeError: raise AttributeError( "This method only works with the ScalarFormatter.") diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 442517df6400..40e3a2ba5780 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -449,6 +449,7 @@ def __call__(self, s): # use scientific notation if log10 # of the axis range is smaller than the # first or larger than the second + 'axes.formatter.use_locale' : [False, validate_bool], # Use the current locale to format ticks 'axes.unicode_minus' : [True, validate_bool], 'axes.color_cycle' : [['b','g','r','c','m','y','k'], validate_colorlist], # cycle of plot diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 34b4d4e6ff38..bc2e263d83b4 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -126,6 +126,7 @@ from __future__ import division import decimal +import locale import math import numpy as np from matplotlib import rcParams @@ -330,7 +331,7 @@ class ScalarFormatter(Formatter): """ - def __init__(self, useOffset=True, useMathText=False): + def __init__(self, useOffset=True, useMathText=False, useLocale=None): # useOffset allows plotting small data ranges with large offsets: # for example: [1+1e-9,1+2e-9,1+3e-9] # useMathText will render the offset and scientific notation in mathtext @@ -341,6 +342,10 @@ def __init__(self, useOffset=True, useMathText=False): self.format = '' self._scientific = True self._powerlimits = rcParams['axes.formatter.limits'] + if useLocale is None: + self._useLocale = rcParams['axes.formatter.use_locale'] + else: + self._useLocale = useLocale def get_useOffset(self): return self._useOffset @@ -355,6 +360,17 @@ def set_useOffset(self, val): useOffset = property(fget=get_useOffset, fset=set_useOffset) + def get_useLocale(self): + return self._useLocale + + def set_useLocale(self, val): + if val is None: + self._useLocale = rcParams['axes.formatter.use_locale'] + else: + self._useLocale = val + + useLocale = property(fget=get_useLocale, fset=set_useLocale) + def fix_minus(self, s): 'use a unicode minus rather than hyphen' if rcParams['text.usetex'] or not rcParams['axes.unicode_minus']: return s @@ -388,11 +404,18 @@ def set_powerlimits(self, lims): def format_data_short(self,value): 'return a short formatted string representation of a number' - return '%-12g'%value + if self._useLocale: + return locale.format_string('%-12g', (value,)) + else: + return '%-12g'%value def format_data(self,value): 'return a formatted string representation of a number' - s = self._formatSciNotation('%1.10e'% value) + if self._useLocale: + s = locale.format_string('%1.10e', (value,)) + else: + s = '%1.10e' % value + s = self._formatSciNotation(s) return self.fix_minus(s) @@ -491,14 +514,23 @@ def _set_format(self): def pprint_val(self, x): xp = (x-self.offset)/10**self.orderOfMagnitude if np.absolute(xp) < 1e-8: xp = 0 - return self.format % xp + if self._useLocale: + return locale.format_string(self.format, (xp,)) + else: + return self.format % xp def _formatSciNotation(self, s): # transform 1e+004 into 1e4, for example + if self._useLocale: + decimal_point = locale.localeconv()['decimal_point'] + positive = locale.localeconv()['positive_sign'] + else: + decimal_point = '.' + positive_sign = '+' tup = s.split('e') try: - significand = tup[0].rstrip('0').rstrip('.') - sign = tup[1][0].replace('+', '') + significand = tup[0].rstrip('0').rstrip(decimal_point) + sign = tup[1][0].replace(positive_sign, '') exponent = tup[1][1:].lstrip('0') if self._useMathText or self._usetex: if significand == '1': diff --git a/matplotlibrc.template b/matplotlibrc.template index 940e0dc23278..a1675fe46170 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -212,6 +212,8 @@ backend : %(backend)s #axes.formatter.limits : -7, 7 # use scientific notation if log10 # of the axis range is smaller than the # first or larger than the second +#axes.formatter.use_locale : False # When True, format tick labels according to the user's locale. + # For example, use ',' as a decimal separator in the fr_FR locale. #axes.unicode_minus : True # use unicode for the minus symbol # rather than hypen. See http://en.wikipedia.org/wiki/Plus_sign#Plus_sign #axes.color_cycle : b, g, r, c, m, y, k # color cycle for plot lines From c7c275d756b8488bfcad5a5a78e529e4db0bd3f0 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 1 Aug 2011 10:54:20 -0400 Subject: [PATCH 065/214] If the user says it's ok to use their locale, use it so we get a correct value for preferred encoding. Printing localized dates is not possible without this. --- lib/matplotlib/cbook.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 36ffe396fb42..445a713357aa 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -29,13 +29,15 @@ # side effects. Passing False eliminates those side effects. try: - preferredencoding = locale.getpreferredencoding(False).strip() + preferredencoding = locale.getpreferredencoding( + matplotlib.rcParams['axes.formatter.use_locale']).strip() if not preferredencoding: preferredencoding = None except (ValueError, ImportError, AttributeError): preferredencoding = None def unicode_safe(s): + print preferredencoding, type(s) if preferredencoding is None: return unicode(s) else: return unicode(s, preferredencoding) From ab8283fc7613960a8b796af9da4507d85a05132a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 1 Aug 2011 12:42:58 -0400 Subject: [PATCH 066/214] Remove errant print statement. --- lib/matplotlib/cbook.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 445a713357aa..58259ae85d8d 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -37,7 +37,6 @@ preferredencoding = None def unicode_safe(s): - print preferredencoding, type(s) if preferredencoding is None: return unicode(s) else: return unicode(s, preferredencoding) From 7a540d4c9a999f2b7b283c531a54325b8bdbf847 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Wed, 3 Aug 2011 15:08:46 -0500 Subject: [PATCH 067/214] Updated the docs with respect to can_zoom() and can_pan(). --- lib/matplotlib/axes.py | 4 ++-- lib/matplotlib/projections/polar.py | 10 ++++++++-- lib/mpl_toolkits/mplot3d/axes3d.py | 10 ++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f192e2471022..bfac1369c4ef 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2777,13 +2777,13 @@ def format_coord(self, x, y): def can_zoom(self): """ - Return *True* if this axes support the zoom box + Return *True* if this axes support the zoom box button functionality. """ return True def can_pan(self) : """ - Return *True* if this axes support the pan action + Return *True* if this axes supports any pan/zoom button functionality. """ return True diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 6a6902a72c39..ec5526cddcb1 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -572,13 +572,19 @@ def get_data_ratio(self): def can_zoom(self): """ - Return True if this axes support the zoom box + Return *True* if this axes supports the zoom box button functionality. + + Polar axes do not support zoom boxes. """ return False def can_pan(self) : """ - Return True if this axes support the pan action + Return *True* if this axes supports the pan/zoom button functionality. + + For polar axes, this is slightly misleading. Both panning and + zooming are performed by the same button. Panning is performed + in azimuth while zooming is done along the radial. """ return True diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 9045e2974b35..65be58e1dd16 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -806,9 +806,19 @@ def mouse_init(self, rotate_btn=1, zoom_btn=3): self._zoom_btn = np.atleast_1d(zoom_btn) def can_zoom(self) : + """ + Return *True* if this axes supports the zoom box button functionality. + + 3D axes objects do not use the zoom box button. + """ return False def can_pan(self) : + """ + Return *True* if this axes supports the pan/zoom button functionality. + + 3D axes objects do not use the pan/zoom button. + """ return False def cla(self): From 261cb76bf27f418bd9c9fad64eebb5548f69f39c Mon Sep 17 00:00:00 2001 From: Ben Root Date: Wed, 3 Aug 2011 19:01:48 -0500 Subject: [PATCH 068/214] Made similar doc changes in geo.py. Also some code style fixes. --- lib/matplotlib/backend_bases.py | 14 ++++++++------ lib/matplotlib/projections/geo.py | 8 ++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 620f24e006cd..4d7bcd43a35b 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -2512,12 +2512,13 @@ def press_pan(self, event): self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): - if x is not None and y is not None and a.in_axes(event) \ - and a.get_navigate() and a.can_pan() : + if (x is not None and y is not None and a.in_axes(event) and + a.get_navigate() and a.can_pan()) : a.start_pan(x, y, event.button) self._xypress.append((a, i)) self.canvas.mpl_disconnect(self._idDrag) - self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan) + self._idDrag=self.canvas.mpl_connect('motion_notify_event', + self.drag_pan) self.press(event) @@ -2538,9 +2539,10 @@ def press_zoom(self, event): self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): - if x is not None and y is not None and a.in_axes(event) \ - and a.get_navigate() and a.can_zoom(): - self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen())) + if (x is not None and y is not None and a.in_axes(event) and + a.get_navigate() and a.can_zoom()) : + self._xypress.append(( x, y, a, i, a.viewLim.frozen(), + a.transData.frozen() )) id1 = self.canvas.mpl_connect('motion_notify_event', self.drag_zoom) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 37933dcd2caf..8a20f5c2768d 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -218,13 +218,17 @@ def get_data_ratio(self): def can_zoom(self): """ - Return True if this axes support the zoom box + Return *True* if this axes supports the zoom box button functionality. + + This axes object does not support interactive zoom box. """ return False def can_pan(self) : """ - Return True if this axes support the pan action + Return *True* if this axes supports the pan/zoom button functionality. + + This axes object does not support interactive pan/zoom. """ return False From aa0f04e1faf584328e6f301a0d3e5a87ee7027fd Mon Sep 17 00:00:00 2001 From: Ben Root Date: Wed, 3 Aug 2011 19:45:35 -0500 Subject: [PATCH 069/214] Fixed a minor typo I made in one of the can_pan docs. --- lib/matplotlib/axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index bfac1369c4ef..81d043f6d7a5 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2777,7 +2777,7 @@ def format_coord(self, x, y): def can_zoom(self): """ - Return *True* if this axes support the zoom box button functionality. + Return *True* if this axes supports the zoom box button functionality. """ return True From 93e2efd5c82242fb2e19463d29e65d04601d1e8c Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 8 Aug 2011 23:50:03 +0900 Subject: [PATCH 070/214] restore 'None' (a string) as a valid marker style (draw nothing) --- lib/matplotlib/markers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index 6b6612490a78..cd0116031aa7 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -90,6 +90,7 @@ class MarkerStyle: CARETRIGHT : 'caretright', CARETUP : 'caretup', CARETDOWN : 'caretdown', + "None" : 'nothing', None : 'nothing', ' ' : 'nothing', '' : 'nothing' From 5bbaeee89afd21f209ef6a1784c1726fe61c6f9b Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Tue, 9 Aug 2011 00:04:19 +0900 Subject: [PATCH 071/214] Use set_marker() in legend_handler.py. Closes #412 --- lib/matplotlib/legend_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index e814e844097c..85790690061b 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -196,7 +196,7 @@ def create_artists(self, legend, orig_handle, #legline.set_clip_box(None) #legline.set_clip_path(None) legline.set_drawstyle('default') - legline.set_marker('None') + legline.set_marker("") legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)]) From 0679e935f464f01306a8321ed5cb15670b2eec2f Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Wed, 10 Aug 2011 10:06:45 +0900 Subject: [PATCH 072/214] fix axisartist behavior when axis limit is inverted --- lib/mpl_toolkits/axisartist/axislines.py | 33 ++++++++++++++++++ lib/mpl_toolkits/axisartist/clip_path.py | 43 ++++++++++++++++++++---- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index a254883da90f..1c9f384f2a74 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -767,6 +767,39 @@ def get_tightbbox(self, renderer): return _bbox + def set_xlim(self, left=None, right=None, emit=True, auto=False, + swap_axis=True, **kw): + + x1o, x2o = self.get_xlim() + + maxes.Axes.set_xlim(self, left, right, emit, auto, **kw) + x1, x2 = self.get_xlim() + + if not swap_axis: + return + + if (x1o > x2o and x1 < x2) or (x1o < x2o and x1 > x2): + self.axis["right"], self.axis["left"] = self.axis["left"], self.axis["right"] + + self.axis["left"].set_axis_direction("left") + self.axis["right"].set_axis_direction("right") + + + def set_ylim(self, bottom=None, top=None, emit=True, auto=False, + swap_axis=True, **kw): + + y1o, y2o = self.get_ylim() + + maxes.Axes.set_ylim(self, bottom, top, emit, auto, **kw) + y1, y2 = self.get_ylim() + + if y1o > y2o and y1 < y2 or (y1o < y2o and y1 > y2): + self.axis["top"], self.axis["bottom"] = self.axis["bottom"], self.axis["top"] + + self.axis["top"].set_axis_direction("top") + self.axis["bottom"].set_axis_direction("bottom") + + Subplot = maxes.subplot_class_factory(Axes) diff --git a/lib/mpl_toolkits/axisartist/clip_path.py b/lib/mpl_toolkits/axisartist/clip_path.py index f863468ce468..04f972765580 100644 --- a/lib/mpl_toolkits/axisartist/clip_path.py +++ b/lib/mpl_toolkits/axisartist/clip_path.py @@ -12,13 +12,24 @@ def atan2(dy, dx): # FIXME : The current algorithm seems to return incorrect angle when the line # ends at the boundary. -def clip(xlines, ylines, x0, clip="right"): +def clip(xlines, ylines, x0, clip="right", xdir=True, ydir=True): clipped_xlines = [] clipped_ylines = [] _pos_angles = [] + if xdir: + xsign = 1 + else: + xsign = -1 + + if ydir: + ysign = 1 + else: + ysign = -1 + + for x, y in zip(xlines, ylines): if clip in ["up", "right"]: @@ -49,7 +60,7 @@ def clip(xlines, ylines, x0, clip="right"): dx = x[i+1] - x[i] dy = y[i+1] - y[i] - a = degrees(atan2(dy, dx)) + a = degrees(atan2(ysign*dy, xsign*dx)) _pos_angles.append((x0, y0, a)) elif c == 1: @@ -63,7 +74,7 @@ def clip(xlines, ylines, x0, clip="right"): dx = x[i+1] - x[i] dy = y[i+1] - y[i] - a = degrees(atan2(dy, dx)) + a = degrees(atan2(ysign*dy, xsign*dx)) _pos_angles.append((x0, y0, a)) #print x[i], x[i+1] @@ -82,10 +93,28 @@ def clip_line_to_rect(xline, yline, bbox): x0, y0, x1, y1 = bbox.extents - lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right") - lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left") - ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right") - ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left") + xdir = x1 > x0 + ydir = y1 > y0 + + if x1 > x0: + lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right", xdir=xdir, ydir=ydir) + lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left", xdir=xdir, ydir=ydir) + else: + lx1, ly1, c_right_ = clip([xline], [yline], x0, clip="right", xdir=xdir, ydir=ydir) + lx2, ly2, c_left_ = clip(lx1, ly1, x1, clip="left", xdir=xdir, ydir=ydir) + + if y1 > y0: + ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right", xdir=ydir, ydir=xdir) + ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left", xdir=ydir, ydir=xdir) + else: + ly3, lx3, c_top_ = clip(ly2, lx2, y0, clip="right", xdir=ydir, ydir=xdir) + ly4, lx4, c_bottom_ = clip(ly3, lx3, y1, clip="left", xdir=ydir, ydir=xdir) + + + # lx1, ly1, c_right_ = clip([xline], [yline], x1, clip="right") + # lx2, ly2, c_left_ = clip(lx1, ly1, x0, clip="left") + # ly3, lx3, c_top_ = clip(ly2, lx2, y1, clip="right") + # ly4, lx4, c_bottom_ = clip(ly3, lx3, y0, clip="left") #c_left = [((x, y), (a+90)%180-180) for (x, y, a) in c_left_ \ # if bbox.containsy(y)] From 4bafdfc4ecf45d11e764435a94d2225b58744739 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Fri, 12 Aug 2011 20:25:57 -1000 Subject: [PATCH 073/214] docstring: clarify usage of Figure.add_axes --- lib/matplotlib/figure.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 2ee5c1e7806b..de9c1a934cc6 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -633,27 +633,28 @@ def fixlist(args): @docstring.dedent_interpd def add_axes(self, *args, **kwargs): """ - Add an a axes with axes rect [*left*, *bottom*, *width*, + Add an axes at position *rect* [*left*, *bottom*, *width*, *height*] where all quantities are in fractions of figure width and height. kwargs are legal :class:`~matplotlib.axes.Axes` kwargs plus *projection* which sets the projection type of the axes. (For backward compatibility, ``polar=True`` may also be provided, which is equivalent to ``projection='polar'``). Valid values for - *projection* are: %(projection_names)s. Some of these projections support - additional kwargs, which may be provided to :meth:`add_axes`:: + *projection* are: %(projection_names)s. Some of these + projections support additional kwargs, which may be provided + to :meth:`add_axes`. Typical usage:: rect = l,b,w,h fig.add_axes(rect) fig.add_axes(rect, frameon=False, axisbg='g') fig.add_axes(rect, polar=True) fig.add_axes(rect, projection='polar') - fig.add_axes(ax) # add an Axes instance + fig.add_axes(ax) If the figure already has an axes with the same parameters, then it will simply make that axes current and return it. If - you do not want this behavior, eg. you want to force the - creation of a new axes, you must use a unique set of args and + you do not want this behavior, e.g. you want to force the + creation of a new Axes, you must use a unique set of args and kwargs. The axes :attr:`~matplotlib.axes.Axes.label` attribute has been exposed for this purpose. Eg., if you want two axes that are otherwise identical to be added to the @@ -662,9 +663,18 @@ def add_axes(self, *args, **kwargs): fig.add_axes(rect, label='axes1') fig.add_axes(rect, label='axes2') - The :class:`~matplotlib.axes.Axes` instance will be returned. + In rare circumstances, add_axes may be called with a single + argument, an Axes instance already created in the present + figure but not in the figure's list of axes. For example, + if an axes has been removed with :meth:`delaxes`, it can + be restored with:: - The following kwargs are supported: + fig.add_axes(ax) + + In all cases, the :class:`~matplotlib.axes.Axes` instance + will be returned. + + In addition to *projection*, the following kwargs are supported: %(Axes)s """ @@ -1321,7 +1331,7 @@ def tight_layout(self, renderer=None, pad=1.2, h_pad=None, w_pad=None): nrows_list = [] ncols_list = [] ax_bbox_list = [] - + subplot_dict = {} # for axes_grid1, multiple axes can share # same subplot_interface. Thus we need to # join them together. @@ -1348,7 +1358,7 @@ def tight_layout(self, renderer=None, pad=1.2, h_pad=None, w_pad=None): subplotspec_list.append(subplotspec) subplot_list.append(subplots) ax_bbox_list.append(subplotspec.get_position(self)) - + subplots.append(ax) max_nrows = max(nrows_list) From 2b6ac8aeb025887c715851271fbbde3b38cae98d Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 14 Aug 2011 10:04:11 -1000 Subject: [PATCH 074/214] docs: remove some svn references, increment version --- doc/_templates/indexsidebar.html | 10 ++++----- doc/devel/coding_guide.rst | 35 +++++++++++--------------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index b84cc6b519fe..c3766755c84b 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -5,7 +5,7 @@

News

to support matplotlib development.

-

matplotlib 1.0.1 is available for download. See what's new and tips on download. See what's new and tips on installing

@@ -16,7 +16,7 @@

News

at amazon.

Build websites like matplotlib's, -with sphinx and extensions for +with Sphinx and extensions for mpl plots, math, inheritance diagrams -- try the sampledoc tutorial. @@ -38,7 +38,7 @@

Videos

Toolkits

-

There are several matplotlib addon toolkits, including the projection and mapping toolkit basemap, 3d plotting with tracker, +github +tracker, but it is a good idea to ping us on the mailing list too.

For details on what's new, see the detailed Date: Sun, 14 Aug 2011 11:31:22 -1000 Subject: [PATCH 076/214] docs: update ipython_directive.py to latest version from ipython git --- lib/matplotlib/sphinxext/ipython_directive.py | 772 ++++++++++++------ 1 file changed, 509 insertions(+), 263 deletions(-) diff --git a/lib/matplotlib/sphinxext/ipython_directive.py b/lib/matplotlib/sphinxext/ipython_directive.py index e7a1aa529097..543b41a9ad79 100644 --- a/lib/matplotlib/sphinxext/ipython_directive.py +++ b/lib/matplotlib/sphinxext/ipython_directive.py @@ -1,38 +1,105 @@ -import sys, os, shutil, imp, warnings, cStringIO, re - -import IPython -from IPython.Shell import MatplotlibShell - +# -*- coding: utf-8 -*- +"""Sphinx directive to support embedded IPython code. + +This directive allows pasting of entire interactive IPython sessions, prompts +and all, and their code will actually get re-executed at doc build time, with +all prompts renumbered sequentially. It also allows you to input code as a pure +python input by giving the argument python to the directive. The output looks +like an interactive ipython section. + +To enable this directive, simply list it in your Sphinx ``conf.py`` file +(making sure the directory where you placed it is visible to sphinx, as is +needed for all Sphinx directives). + +By default this directive assumes that your prompts are unchanged IPython ones, +but this can be customized. The configurable options that can be placed in +conf.py are + +ipython_savefig_dir: + The directory in which to save the figures. This is relative to the + Sphinx source directory. The default is `html_static_path`. +ipython_rgxin: + The compiled regular expression to denote the start of IPython input + lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You + shouldn't need to change this. +ipython_rgxout: + The compiled regular expression to denote the start of IPython output + lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You + shouldn't need to change this. +ipython_promptin: + The string to represent the IPython input prompt in the generated ReST. + The default is 'In [%d]:'. This expects that the line numbers are used + in the prompt. +ipython_promptout: + + The string to represent the IPython prompt in the generated ReST. The + default is 'Out [%d]:'. This expects that the line numbers are used + in the prompt. + +ToDo +---- + +- Turn the ad-hoc test() function into a real test suite. +- Break up ipython-specific functionality from matplotlib stuff into better + separated code. + +Authors +------- + +- John D Hunter: orignal author. +- Fernando Perez: refactoring, documentation, cleanups, port to 0.11. +- VáclavÃ… milauer : Prompt generalizations. +- Skipper Seabold, refactoring, cleanups, pure python addition +""" + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +# Stdlib +import cStringIO +import os +import re +import sys +import tempfile + +# To keep compatibility with various python versions try: from hashlib import md5 except ImportError: from md5 import md5 -from docutils.parsers.rst import directives +# Third-party +import matplotlib import sphinx +from docutils.parsers.rst import directives +from docutils import nodes +from sphinx.util.compat import Directive +matplotlib.use('Agg') -sphinx_version = sphinx.__version__.split(".") -# The split is necessary for sphinx beta versions where the string is -# '6b1' -sphinx_version = tuple([int(re.split('[a-z]', x)[0]) - for x in sphinx_version[:2]]) - - +# Our own +from IPython import Config, InteractiveShell +from IPython.core.profiledir import ProfileDir +from IPython.utils import io +#----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- +# for tokenizing blocks COMMENT, INPUT, OUTPUT = range(3) -rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*') -rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*') -fmtin = 'In [%d]:' -fmtout = 'Out[%d]:' -def block_parser(part): +#----------------------------------------------------------------------------- +# Functions and class declarations +#----------------------------------------------------------------------------- +def block_parser(part, rgxin, rgxout, fmtin, fmtout): """ part is a string of ipython text, comprised of at most one input, one ouput, comments, and blank lines. The block parser parses the text into a list of:: blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...] + where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and data is, depending on the type of token:: @@ -45,12 +112,10 @@ def block_parser(part): OUTPUT: the output string, possibly multi-line - """ block = [] lines = part.split('\n') - #print 'PARSE', lines N = len(lines) i = 0 decorator = None @@ -67,7 +132,6 @@ def block_parser(part): block.append((COMMENT, line)) continue - if line_stripped.startswith('@'): # we're assuming at most one decorator -- may need to # rethink @@ -117,36 +181,50 @@ def block_parser(part): if i2: + if debug: + print '\n'.join(lines) + else: #NOTE: this raises some errors, what's it for? + #print 'INSERTING %d lines'%len(lines) + self.state_machine.insert_input( + lines, self.state_machine.input_lines.source(0)) - #print lines - if len(lines)>2: - if debug: - print '\n'.join(lines) - else: - #print 'INSERTING %d lines'%len(lines) - state_machine.insert_input( - lines, state_machine.input_lines.source(0)) + text = '\n'.join(lines) + txtnode = nodes.literal_block(text, text) + txtnode['language'] = 'ipython' + #imgnode = nodes.image(figs) - return [] + # cleanup + self.teardown() -ipython_directive.DEBUG = False + return []#, imgnode] +# Enable as a proper Sphinx directive def setup(app): setup.app = app - options = { - 'suppress': directives.flag, - 'doctest': directives.flag, - 'verbatim': directives.flag, - } - - app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options) + app.add_directive('ipython', IpythonDirective) + app.add_config_value('ipython_savefig_dir', None, True) + app.add_config_value('ipython_rgxin', + re.compile('In \[(\d+)\]:\s?(.*)\s*'), True) + app.add_config_value('ipython_rgxout', + re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True) + app.add_config_value('ipython_promptin', 'In [%d]:', True) + app.add_config_value('ipython_promptout', 'Out[%d]:', True) +# Simple smoke test, needs to be converted to a proper automatic test. def test(): examples = [ @@ -429,7 +705,6 @@ def test(): .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' In [131]: print url.split('&') ---------> print(url.split('&')) ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv'] In [60]: import urllib @@ -443,7 +718,7 @@ def test(): In [134]: numpy.random.seed(2358) @doctest -In [135]: np.random.rand(10,2) +In [135]: numpy.random.rand(10,2) Out[135]: array([[ 0.64524308, 0.59943846], [ 0.47102322, 0.8715456 ], @@ -460,7 +735,6 @@ def test(): r""" In [106]: print x ---------> print(x) jdh In [109]: for i in range(10): @@ -477,8 +751,6 @@ def test(): 7 8 9 - - """, r""" @@ -518,41 +790,12 @@ def test(): In [153]: grid(True) """, + ] + # skip local-file depending first example: + examples = examples[1:] - - r""" - -In [239]: 1/2 -@verbatim -Out[239]: 0 - -In [240]: 1.0/2.0 -Out[240]: 0.5 -""", - - r""" -@verbatim -In [6]: pwd -Out[6]: '/home/jdhunter/mypy' -""", - - r""" -@verbatim -In [151]: myfile.upper? -Type: builtin_function_or_method -Base Class: -String Form: -Namespace: Interactive -Docstring: - S.upper() -> string - Return a copy of the string S converted to uppercase. - """ - ] - - - - ipython_directive.DEBUG = True - #options = dict(suppress=True) + #ipython_directive.DEBUG = True # dbg + #options = dict(suppress=True) # dbg options = dict() for example in examples: content = example.split('\n') @@ -562,6 +805,9 @@ def test(): state=None, state_machine=None, ) - +# Run test suite as a script if __name__=='__main__': + if not os.path.isdir('_static'): + os.mkdir('_static') test() + print 'All OK? Check figures in _static/' From 0f50185a83474dc6c6a6cde3b1ed693850178a01 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 14 Aug 2011 12:31:18 -1000 Subject: [PATCH 077/214] doc sidebar: point to 1.1.0 for download --- doc/_templates/indexsidebar.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index c3766755c84b..37a9f2e3bf15 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -5,8 +5,10 @@

News

to support matplotlib development.

-

Matplotlib 1.1.0 is available for download. See what's new and tips on installing +

Matplotlib 1.1.0 is available for +download. +See what's new +and tips on installing.

Sandro Tosi has a new book From 40686cb03e44c5e98d2b0179b4d90d870b9b34d1 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 15 Aug 2011 15:51:50 +0900 Subject: [PATCH 078/214] axes_grid1: fix an error in HostAxesBase._get_legend_handles --- lib/mpl_toolkits/axes_grid1/parasite_axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpl_toolkits/axes_grid1/parasite_axes.py b/lib/mpl_toolkits/axes_grid1/parasite_axes.py index 282c4843a274..39a7d981020f 100644 --- a/lib/mpl_toolkits/axes_grid1/parasite_axes.py +++ b/lib/mpl_toolkits/axes_grid1/parasite_axes.py @@ -260,7 +260,7 @@ def _get_legend_handles(self, legend_handler_map=None): all_handles = Axes_get_legend_handles(self, legend_handler_map) for ax in self.parasites: - all_handles.extend(ax._get_legend_handles) + all_handles.extend(ax._get_legend_handles(legend_handler_map)) return all_handles From 747baecd109f1ade2c97d6e86f54bb39d3de0eb8 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Mon, 15 Aug 2011 13:32:03 -1000 Subject: [PATCH 079/214] docs: fix various example plots; add info to plot_directive warnings --- doc/pyplots/plotmap.py | 26 +++- doc/pyplots/tex_demo.png | Bin 18781 -> 0 bytes examples/pylab_examples/demo_tight_layout.py | 129 +++++++++---------- examples/units/artist_tests.py | 29 +++-- examples/units/evans_test.py | 20 ++- lib/matplotlib/sphinxext/plot_directive.py | 3 +- 6 files changed, 114 insertions(+), 93 deletions(-) delete mode 100644 doc/pyplots/tex_demo.png diff --git a/doc/pyplots/plotmap.py b/doc/pyplots/plotmap.py index 02f12b7a4d41..98a5d64bb135 100644 --- a/doc/pyplots/plotmap.py +++ b/doc/pyplots/plotmap.py @@ -1,8 +1,14 @@ +import matplotlib.pyplot as plt +import numpy as np + try: from mpl_toolkits.basemap import Basemap - import matplotlib.pyplot as plt - import numpy as np + have_basemap = True +except ImportError: + have_basemap = False + +def plotmap(): # create figure fig = plt.figure(figsize=(8,8)) # set up orthographic map projection with @@ -40,6 +46,16 @@ # draw blue marble image in background. # (downsample the image by 50% for speed) map.bluemarble(scale=0.5) - plt.show() -except ImportError: - pass + +def plotempty(): + # create figure + fig = plt.figure(figsize=(8,8)) + fig.text(0.5, 0.5, "Sorry, could not import Basemap", + horizontalalignment='center') + +if have_basemap: + plotmap() +else: + plotempty() +plt.show() + diff --git a/doc/pyplots/tex_demo.png b/doc/pyplots/tex_demo.png deleted file mode 100644 index 75e0f852d873ef04aaf2c20a30b7ed972a5b5134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18781 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 diff --git a/examples/pylab_examples/demo_tight_layout.py b/examples/pylab_examples/demo_tight_layout.py index 2f01b159692e..e428a7b28a56 100644 --- a/examples/pylab_examples/demo_tight_layout.py +++ b/examples/pylab_examples/demo_tight_layout.py @@ -10,97 +10,96 @@ def example_plot(ax): ax.set_ylabel('y-label', fontsize=random.choice(fontsizes)) ax.set_title('Title', fontsize=random.choice(fontsizes)) -if 1: - fig, ax = plt.subplots() - example_plot(ax) - plt.tight_layout() +fig, ax = plt.subplots() +example_plot(ax) +plt.tight_layout() - fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - example_plot(ax4) - plt.tight_layout() +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) +plt.tight_layout() - fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1) - example_plot(ax1) - example_plot(ax2) - plt.tight_layout() +fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1) +example_plot(ax1) +example_plot(ax2) +plt.tight_layout() - fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) - example_plot(ax1) - example_plot(ax2) - plt.tight_layout() +fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) +example_plot(ax1) +example_plot(ax2) +plt.tight_layout() - fig, axes = plt.subplots(nrows=3, ncols=3) - for row in axes: - for ax in row: - example_plot(ax) - plt.tight_layout() +fig, axes = plt.subplots(nrows=3, ncols=3) +for row in axes: + for ax in row: + example_plot(ax) +plt.tight_layout() - fig = plt.figure() +fig = plt.figure() - ax1 = plt.subplot(221) - ax2 = plt.subplot(223) - ax3 = plt.subplot(122) +ax1 = plt.subplot(221) +ax2 = plt.subplot(223) +ax3 = plt.subplot(122) - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) - plt.tight_layout() +plt.tight_layout() - fig = plt.figure() +fig = plt.figure() - ax1 = plt.subplot2grid((3, 3), (0, 0)) - ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) - ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) - ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) +ax1 = plt.subplot2grid((3, 3), (0, 0)) +ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) +ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) +ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - example_plot(ax4) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) - plt.tight_layout() +plt.tight_layout() - plt.show() +plt.show() - fig = plt.figure() +fig = plt.figure() - import matplotlib.gridspec as gridspec +import matplotlib.gridspec as gridspec - gs1 = gridspec.GridSpec(3, 1) - ax1 = fig.add_subplot(gs1[0]) - ax2 = fig.add_subplot(gs1[1]) - ax3 = fig.add_subplot(gs1[2]) +gs1 = gridspec.GridSpec(3, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) +ax3 = fig.add_subplot(gs1[2]) - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) - gs1.tight_layout(fig, rect=[None, None, 0.45, None]) +gs1.tight_layout(fig, rect=[None, None, 0.45, None]) - gs2 = gridspec.GridSpec(2, 1) - ax4 = fig.add_subplot(gs2[0]) - ax5 = fig.add_subplot(gs2[1]) +gs2 = gridspec.GridSpec(2, 1) +ax4 = fig.add_subplot(gs2[0]) +ax5 = fig.add_subplot(gs2[1]) - #example_plot(ax4) - #example_plot(ax5) +#example_plot(ax4) +#example_plot(ax5) - gs2.tight_layout(fig, rect=[0.45, None, None, None]) +gs2.tight_layout(fig, rect=[0.45, None, None, None]) - # now match the top and bottom of two gridspecs. - top = min(gs1.top, gs2.top) - bottom = max(gs1.bottom, gs2.bottom) +# now match the top and bottom of two gridspecs. +top = min(gs1.top, gs2.top) +bottom = max(gs1.bottom, gs2.bottom) - gs1.update(top=top, bottom=bottom) - gs2.update(top=top, bottom=bottom) - - plt.show() +gs1.update(top=top, bottom=bottom) +gs2.update(top=top, bottom=bottom) + +plt.show() diff --git a/examples/units/artist_tests.py b/examples/units/artist_tests.py index cc5d757e8e32..aa88496085f5 100644 --- a/examples/units/artist_tests.py +++ b/examples/units/artist_tests.py @@ -15,28 +15,33 @@ from basic_units import cm, inch import numpy as np -from pylab import figure, show +from matplotlib.pyplot import figure, show fig = figure() ax = fig.add_subplot(111) ax.xaxis.set_units(cm) ax.yaxis.set_units(cm) -# test a line collection -verts = [] -for i in range(10): - # a random line segment in inches - verts.append(zip(*inch*10*np.random.rand(2, random.randint(2,15)))) -lc = collections.LineCollection(verts, axes=ax) -ax.add_collection(lc) +if 0: + # test a line collection + # Not supported at present. + verts = [] + for i in range(10): + # a random line segment in inches + verts.append(zip(*inch*10*np.random.rand(2, random.randint(2,15)))) + lc = collections.LineCollection(verts, axes=ax) + ax.add_collection(lc) # test a plain-ol-line line = lines.Line2D([0*cm, 1.5*cm], [0*cm, 2.5*cm], lw=2, color='black', axes=ax) ax.add_line(line) -# test a patch -rect = patches.Rectangle( (1*cm, 1*cm), width=5*cm, height=2*cm, alpha=0.2, axes=ax) -ax.add_patch(rect) +if 0: + # test a patch + # Not supported at present. + rect = patches.Rectangle( (1*cm, 1*cm), width=5*cm, height=2*cm, alpha=0.2, axes=ax) + ax.add_patch(rect) + t = text.Text(3*cm, 2.5*cm, 'text label', ha='left', va='bottom', axes=ax) ax.add_artist(t) @@ -45,4 +50,6 @@ ax.set_ylim(-1*cm, 10*cm) #ax.xaxis.set_units(inch) ax.grid(True) +ax.set_title("Artists with units") show() + diff --git a/examples/units/evans_test.py b/examples/units/evans_test.py index c26918faee1f..fd91f24576ff 100644 --- a/examples/units/evans_test.py +++ b/examples/units/evans_test.py @@ -6,7 +6,6 @@ """ import matplotlib -matplotlib.rcParams['units'] = True from matplotlib.cbook import iterable import matplotlib.units as units @@ -29,7 +28,7 @@ def axisinfo(unit, axis): 'return the Foo AxisInfo' if unit==1.0 or unit==2.0: return units.AxisInfo( - majloc = ticker.IndexLocator( 4, 0 ), + majloc = ticker.IndexLocator( 8, 0 ), majfmt = ticker.FormatStrFormatter("VAL: %s"), label='foo', ) @@ -73,23 +72,22 @@ def default_units(x, axis): # plot specifying units fig = figure() +fig.suptitle("Custom units") fig.subplots_adjust(bottom=0.2) -ax = fig.add_subplot(111) +ax = fig.add_subplot(1,2,2) ax.plot( x, y, 'o', xunits=2.0 ) for label in ax.get_xticklabels(): label.set_rotation(30) label.set_ha('right') +ax.set_title("xunits = 2.0") -#fig.savefig('plot1.png') # plot without specifying units; will use the None branch for axisinfo -fig2 = figure() -ax = fig2.add_subplot(111) +ax = fig.add_subplot(1,2,1) ax.plot( x, y ) # uses default units -#p.savefig('plot2.png') - -fig3 = figure() -ax = fig3.add_subplot(111) -ax.plot( x, y, xunits=0.5) +ax.set_title('default units') +for label in ax.get_xticklabels(): + label.set_rotation(30) + label.set_ha('right') show() diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index abafc54bccd0..6463d9cbb868 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -687,7 +687,8 @@ def run(arguments, content, options, state_machine, state, lineno): except PlotError, err: reporter = state.memo.reporter sm = reporter.system_message( - 2, "Exception occurred in plotting %s: %s" % (output_base, err), + 2, "Exception occurred in plotting %s\n from %s:\n%s" % (output_base, + source_file_name, err), line=lineno) results = [(code, [])] errors = [sm] From 29ec51b2cfe27f5411319418b1f2bcd1597450c5 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Tue, 16 Aug 2011 10:00:34 -1000 Subject: [PATCH 080/214] matshow: behave well with origin kwarg --- lib/matplotlib/axes.py | 17 +++++++---------- lib/matplotlib/pyplot.py | 7 +++++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f1eab53fc514..d45d20a319f9 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -5770,7 +5770,7 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, marker_obj.get_transform()) if not marker_obj.is_filled(): edgecolors = 'face' - + collection = mcoll.PathCollection( (path,), scales, facecolors = colors, @@ -8214,19 +8214,16 @@ def matshow(self, Z, **kwargs): *Z* anything that can be interpreted as a 2-D array kwargs all are passed to :meth:`~matplotlib.axes.Axes.imshow`. - :meth:`matshow` sets defaults for *extent*, *origin*, - *interpolation*, and *aspect*; use care in overriding the - *extent* and *origin* kwargs, because they interact. (Also, - if you want to change them, you probably should be using - imshow directly in your own version of matshow.) + :meth:`matshow` sets defaults for *origin*, + *interpolation*, and *aspect*; if you want row zero to + be at the bottom instead of the top, you can set the *origin* + kwarg to "lower". Returns: an :class:`matplotlib.image.AxesImage` instance. ''' - Z = np.asarray(Z) + Z = np.asanyarray(Z) nr, nc = Z.shape - extent = [-0.5, nc-0.5, nr-0.5, -0.5] - kw = {'extent': extent, - 'origin': 'upper', + kw = {'origin': 'upper', 'interpolation': 'nearest', 'aspect': 'equal'} # (already the imshow default) kw.update(kwargs) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index e98f0c447231..ab963d4766c9 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -1710,8 +1710,10 @@ def matshow(A, fignum=None, **kw): Tick labels for the xaxis are placed on top. - With the exception of fignum, keyword arguments are passed to - :func:`~matplotlib.pyplot.imshow`. + With the exception of *fignum*, keyword arguments are passed to + :func:`~matplotlib.pyplot.imshow`. You may set the *origin* + kwarg to "lower" if you want the first row in the array to be + at the bottom instead of the top. *fignum*: [ None | integer | False ] @@ -1724,6 +1726,7 @@ def matshow(A, fignum=None, **kw): If *fignum* is *False* or 0, a new figure window will **NOT** be created. """ + A = np.asanyarray(A) if fignum is False or fignum is 0: ax = gca() else: From 8b0ea72acb9f7218e7500da474e7928c1691031e Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Tue, 16 Aug 2011 17:01:35 -0500 Subject: [PATCH 081/214] fix some python2.4 compliance issues --- lib/matplotlib/lines.py | 8 ++++---- lib/matplotlib/sphinxext/plot_directive.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 0dc8ac4ee8a7..c8f1515ccfe7 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -108,7 +108,7 @@ class Line2D(Artist): markers = MarkerStyle.markers filled_markers = MarkerStyle.filled_markers fillStyles = MarkerStyle.fillstyles - + zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') @@ -551,7 +551,7 @@ def draw(self, renderer): renderer.draw_markers( gc, alt_marker_path, alt_marker_trans, subsampled, affine.frozen(), rgbFace) - + gc.restore() gc.restore() @@ -747,9 +747,9 @@ def set_marker(self, marker): """ try: self._marker.set_marker(marker) - except ValueError as e: + except ValueError,e: verbose.report(str(e)) - + def set_markeredgecolor(self, ec): """ Set the marker edge color diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index 6463d9cbb868..98731295f57a 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -578,7 +578,7 @@ def render_figures(code, code_path, output_dir, output_base, context, for format, dpi in formats: try: figman.canvas.figure.savefig(img.filename(format), dpi=dpi) - except exceptions.BaseException as err: + except Exception,err: raise PlotError(traceback.format_exc()) img.formats.append(format) From 4c078ddf68cc0ecc1a5f36009a3e3a8b4921b037 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Tue, 16 Aug 2011 21:50:54 -1000 Subject: [PATCH 082/214] graphics context: use alpha value from foreground color if present When a Line2D color is given as an rgba, this causes the "a" part to be used unless it is explicitly overriden by an alpha kwarg. --- lib/matplotlib/backend_bases.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 4d7bcd43a35b..226cc8132a10 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -742,8 +742,7 @@ def get_linewidth(self): def get_rgb(self): """ - returns a tuple of three floats from 0-1. color can be a - MATLAB format string, a html hex color string, or a rgb tuple + returns a tuple of three or four floats from 0-1. """ return self._rgb @@ -771,9 +770,8 @@ def set_alpha(self, alpha): Set the alpha value used for blending - not supported on all backends """ - if alpha is None: - alpha = 1.0 - self._alpha = alpha + if alpha is not None: + self._alpha = alpha def set_antialiased(self, b): """ @@ -823,17 +821,19 @@ def set_dashes(self, dash_offset, dash_list): def set_foreground(self, fg, isRGB=False): """ Set the foreground color. fg can be a MATLAB format string, a - html hex color string, an rgb unit tuple, or a float between 0 + html hex color string, an rgb or rgba unit tuple, or a float between 0 and 1. In the latter case, grayscale is used. The :class:`GraphicsContextBase` converts colors to rgb - internally. If you know the color is rgb already, you can set + internally. If you know the color is rgb or rgba already, you can set ``isRGB=True`` to avoid the performace hit of the conversion """ if isRGB: self._rgb = fg else: self._rgb = colors.colorConverter.to_rgba(fg) + if len(self._rgb) == 4: + self._alpha = self._rgb[3] def set_graylevel(self, frac): """ From cd5eda481f753fa950a3186137a09a185027a64a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 17 Aug 2011 09:02:56 -0400 Subject: [PATCH 083/214] Don't silently fail when confronted with an unknown marker --- lib/matplotlib/lines.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index c8f1515ccfe7..b57704024265 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -745,11 +745,8 @@ def set_marker(self, marker): %(MarkerAccepts)s """ - try: - self._marker.set_marker(marker) - except ValueError,e: - verbose.report(str(e)) - + self._marker.set_marker(marker) + def set_markeredgecolor(self, ec): """ Set the marker edge color From 96db195e11d06b21902e50c566ea7cce9f3d10af Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 17 Aug 2011 09:21:33 -0400 Subject: [PATCH 084/214] Update test images for small changes in marker outline behavior --- .../baseline_images/test_axes/markevery.png | Bin 33511 -> 33561 bytes .../test_axes/markevery_line.png | Bin 49689 -> 49761 bytes .../test_axes/markevery_line.svg | 1453 ++++++++--------- 3 files changed, 699 insertions(+), 754 deletions(-) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery.png index f1269a1204159b962f5a90bc1762743955686fd7..1cb40c852e2460c3c956c704ac7551438a76fb55 100644 GIT binary patch literal 33561 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 z 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 literal 33511 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 literal 49689 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≻dKu68SS!lH2j8c+l1K( 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 Q))@u=)FBj9pkxvJUvq#`?EnA( diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg index 0db6b71bdd26..2e5f7f168b08 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg @@ -147,109 +147,109 @@ C-2.6839 -1.55874 -3 -0.795609 -3 0 C-3 0.795609 -2.6839 1.55874 -2.12132 2.12132 C-1.55874 2.6839 -0.795609 3 0 3 z -" id="mafc88db4ae"/> +" id="mcc88ba74a7"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -361,109 +361,109 @@ L2.54558 0 L2.44249e-16 -4.24264 L-2.54558 -8.88178e-16 z -" id="m016d603646"/> +" id="m53557f14a9"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -575,19 +575,19 @@ L3 3 L3 -3 L-3 -3 z -" id="mbfa5fcfaff"/> +" id="m63986abc5f"/> - - - - - - - - - - + + + + + + + + + + @@ -697,14 +697,14 @@ L518.4 342.668" style="fill:none;stroke:#00bfbf;"/> M-3 0 L3 0 M0 3 -L0 -3" id="mba139cba6e"/> +L0 -3" id="m042afd644e"/> - - - - - + + + + + @@ -713,46 +713,46 @@ L0 -3" id="mba139cba6e"/> +L0 -4" id="m6584238d7b"/> - + +L0 4" id="m84b0aaa90c"/> - + - @@ -762,50 +762,50 @@ Q19.5312 -74.2188 31.7812 -74.2188" id="BitstreamVeraSans-Roman-30"/> +M31.7812 66.4062 +Q24.1719 66.4062 20.3281 58.9062 +Q16.5 51.4219 16.5 36.375 +Q16.5 21.3906 20.3281 13.8906 +Q24.1719 6.39062 31.7812 6.39062 +Q39.4531 6.39062 43.2812 13.8906 +Q47.125 21.3906 47.125 36.375 +Q47.125 51.4219 43.2812 58.9062 +Q39.4531 66.4062 31.7812 66.4062 +M31.7812 74.2188 +Q44.0469 74.2188 50.5156 64.5156 +Q56.9844 54.8281 56.9844 36.375 +Q56.9844 17.9688 50.5156 8.26562 +Q44.0469 -1.42188 31.7812 -1.42188 +Q19.5312 -1.42188 13.0625 8.26562 +Q6.59375 17.9688 6.59375 36.375 +Q6.59375 54.8281 13.0625 64.5156 +Q19.5312 74.2188 31.7812 74.2188" id="BitstreamVeraSans-Roman-30"/> + +L0 -4" id="m6584238d7b"/> - + +L0 4" id="m84b0aaa90c"/> - + - @@ -815,46 +815,46 @@ Q31.1094 -20.4531 19.1875 -8.29688" id="BitstreamVeraSans-Roman-32"/> +L7.32812 8.29688 +Q12.9375 14.1094 22.625 23.8906 +Q32.3281 33.6875 34.8125 36.5312 +Q39.5469 41.8438 41.4219 45.5312 +Q43.3125 49.2188 43.3125 52.7812 +Q43.3125 58.5938 39.2344 62.25 +Q35.1562 65.9219 28.6094 65.9219 +Q23.9688 65.9219 18.8125 64.3125 +Q13.6719 62.7031 7.8125 59.4219 +L7.8125 69.3906 +Q13.7656 71.7812 18.9375 73 +Q24.125 74.2188 28.4219 74.2188 +Q39.75 74.2188 46.4844 68.5469 +Q53.2188 62.8906 53.2188 53.4219 +Q53.2188 48.9219 51.5312 44.8906 +Q49.8594 40.875 45.4062 35.4062 +Q44.1875 33.9844 37.6406 27.2188 +Q31.1094 20.4531 19.1875 8.29688" id="BitstreamVeraSans-Roman-32"/> + +L0 -4" id="m6584238d7b"/> - + +L0 4" id="m84b0aaa90c"/> - + - @@ -864,55 +864,55 @@ z + +L0 -4" id="m6584238d7b"/> - + +L0 4" id="m84b0aaa90c"/> - + - @@ -922,63 +922,63 @@ Q48.4844 -72.75 52.5938 -71.2969" id="BitstreamVeraSans-Roman-36"/> +M33.0156 40.375 +Q26.375 40.375 22.4844 35.8281 +Q18.6094 31.2969 18.6094 23.3906 +Q18.6094 15.5312 22.4844 10.9531 +Q26.375 6.39062 33.0156 6.39062 +Q39.6562 6.39062 43.5312 10.9531 +Q47.4062 15.5312 47.4062 23.3906 +Q47.4062 31.2969 43.5312 35.8281 +Q39.6562 40.375 33.0156 40.375 +M52.5938 71.2969 +L52.5938 62.3125 +Q48.875 64.0625 45.0938 64.9844 +Q41.3125 65.9219 37.5938 65.9219 +Q27.8281 65.9219 22.6719 59.3281 +Q17.5312 52.7344 16.7969 39.4062 +Q19.6719 43.6562 24.0156 45.9219 +Q28.375 48.1875 33.5938 48.1875 +Q44.5781 48.1875 50.9531 41.5156 +Q57.3281 34.8594 57.3281 23.3906 +Q57.3281 12.1562 50.6875 5.35938 +Q44.0469 -1.42188 33.0156 -1.42188 +Q20.3594 -1.42188 13.6719 8.26562 +Q6.98438 17.9688 6.98438 36.375 +Q6.98438 53.6562 15.1875 63.9375 +Q23.3906 74.2188 37.2031 74.2188 +Q40.9219 74.2188 44.7031 73.4844 +Q48.4844 72.75 52.5938 71.2969" id="BitstreamVeraSans-Roman-36"/> + +L0 -4" id="m6584238d7b"/> - + +L0 4" id="m84b0aaa90c"/> - + - @@ -988,41 +988,41 @@ Q18.3125 -60.0625 18.3125 -54.3906" id="BitstreamVeraSans-Roman-38"/> +M31.7812 34.625 +Q24.75 34.625 20.7188 30.8594 +Q16.7031 27.0938 16.7031 20.5156 +Q16.7031 13.9219 20.7188 10.1562 +Q24.75 6.39062 31.7812 6.39062 +Q38.8125 6.39062 42.8594 10.1719 +Q46.9219 13.9688 46.9219 20.5156 +Q46.9219 27.0938 42.8906 30.8594 +Q38.875 34.625 31.7812 34.625 +M21.9219 38.8125 +Q15.5781 40.375 12.0312 44.7188 +Q8.5 49.0781 8.5 55.3281 +Q8.5 64.0625 14.7188 69.1406 +Q20.9531 74.2188 31.7812 74.2188 +Q42.6719 74.2188 48.875 69.1406 +Q55.0781 64.0625 55.0781 55.3281 +Q55.0781 49.0781 51.5312 44.7188 +Q48 40.375 41.7031 38.8125 +Q48.8281 37.1562 52.7969 32.3125 +Q56.7812 27.4844 56.7812 20.5156 +Q56.7812 9.90625 50.3125 4.23438 +Q43.8438 -1.42188 31.7812 -1.42188 +Q19.7344 -1.42188 13.25 4.23438 +Q6.78125 9.90625 6.78125 20.5156 +Q6.78125 27.4844 10.7812 32.3125 +Q14.7969 37.1562 21.9219 38.8125 +M18.3125 54.3906 +Q18.3125 48.7344 21.8438 45.5625 +Q25.3906 42.3906 31.7812 42.3906 +Q38.1406 42.3906 41.7188 45.5625 +Q45.3125 48.7344 45.3125 54.3906 +Q45.3125 60.0625 41.7188 63.2344 +Q38.1406 66.4062 31.7812 66.4062 +Q25.3906 66.4062 21.8438 63.2344 +Q18.3125 60.0625 18.3125 54.3906" id="BitstreamVeraSans-Roman-38"/> + +L0 -4" id="m6584238d7b"/> - + +L0 4" id="m84b0aaa90c"/> - + - + @@ -1035,41 +1035,41 @@ z +L4 0" id="mb3141632c0"/> - + +L-4 0" id="md4841ec8c2"/> - + - + @@ -1082,52 +1082,52 @@ z +L4 0" id="mb3141632c0"/> - + +L-4 0" id="md4841ec8c2"/> - + - + @@ -1140,25 +1140,25 @@ z +L4 0" id="mb3141632c0"/> - + +L-4 0" id="md4841ec8c2"/> - + - + @@ -1170,25 +1170,25 @@ L-4 0" id="m560f5ef9cf"/> +L4 0" id="mb3141632c0"/> - + +L-4 0" id="md4841ec8c2"/> - + - + @@ -1200,25 +1200,25 @@ L-4 0" id="m560f5ef9cf"/> +L4 0" id="mb3141632c0"/> - + +L-4 0" id="md4841ec8c2"/> - + - + @@ -1230,25 +1230,25 @@ L-4 0" id="m560f5ef9cf"/> +L4 0" id="mb3141632c0"/> - + +L-4 0" id="md4841ec8c2"/> - + - + @@ -1291,24 +1291,6 @@ z - - - - - - - @@ -1323,165 +1305,165 @@ C-2.6839 -1.55874 -3 -0.795609 -3 0 C-3 0.795609 -2.6839 1.55874 -2.12132 2.12132 C-1.55874 2.6839 -0.795609 3 0 3 z -" id="mafc88db4ae"/> +" id="mcc88ba74a7"/> - - + + - +L45.4062 8.20312 +Q42.5781 3.32812 38.25 0.953125 +Q33.9375 -1.42188 27.875 -1.42188 +Q17.9688 -1.42188 11.7344 6.48438 +Q5.51562 14.4062 5.51562 27.2969 +Q5.51562 40.1875 11.7344 48.0938 +Q17.9688 56 27.875 56 +Q33.9375 56 38.25 53.625 +Q42.5781 51.2656 45.4062 46.3906 +M14.7969 27.2969 +Q14.7969 17.3906 18.875 11.75 +Q22.9531 6.10938 30.0781 6.10938 +Q37.2031 6.10938 41.2969 11.75 +Q45.4062 17.3906 45.4062 27.2969 +Q45.4062 37.2031 41.2969 42.8438 +Q37.2031 48.4844 30.0781 48.4844 +Q22.9531 48.4844 18.875 42.8438 +Q14.7969 37.2031 14.7969 27.2969" id="BitstreamVeraSans-Roman-64"/> +L45.3125 8.40625 +Q42.0469 3.42188 37.7188 1 +Q33.4062 -1.42188 27.6875 -1.42188 +Q18.2656 -1.42188 13.375 4.4375 +Q8.5 10.2969 8.5 21.5781" id="BitstreamVeraSans-Roman-75"/> +L43.2188 8.29688 +Q40.1406 3.32812 35.5469 0.953125 +Q30.9531 -1.42188 24.3125 -1.42188 +Q15.9219 -1.42188 10.9531 3.29688 +Q6 8.01562 6 15.9219 +Q6 25.1406 12.1719 29.8281 +Q18.3594 34.5156 30.6094 34.5156 +L43.2188 34.5156 +L43.2188 35.4062 +Q43.2188 41.6094 39.1406 45 +Q35.0625 48.3906 27.6875 48.3906 +Q23 48.3906 18.5469 47.2656 +Q14.1094 46.1406 10.0156 43.8906 +L10.0156 52.2031 +Q14.9375 54.1094 19.5781 55.0469 +Q24.2188 56 28.6094 56 +Q40.4844 56 46.3438 49.8438 +Q52.2031 43.7031 52.2031 31.2031" id="BitstreamVeraSans-Roman-61"/> + @@ -1495,19 +1477,6 @@ Q52.2031 -43.7031 52.2031 -31.2031" id="BitstreamVeraSans-Roman-61"/> - - - - - - - @@ -1517,11 +1486,11 @@ L2.54558 0 L2.44249e-16 -4.24264 L-2.54558 -8.88178e-16 z -" id="m016d603646"/> +" id="m53557f14a9"/> - - + + @@ -1529,67 +1498,67 @@ z - +L9.07812 54.6875 +L18.1094 54.6875 +L18.1094 46.1875 +Q21.1875 51.2188 25.4844 53.6094 +Q29.7812 56 35.6875 56 +Q41.6562 56 45.8281 52.9688 +Q50 49.9531 52 44.1875" id="BitstreamVeraSans-Roman-6d"/> + @@ -1604,19 +1573,6 @@ z - - - - - - - @@ -1626,45 +1582,45 @@ L3 3 L3 -3 L-3 -3 z -" id="mbfa5fcfaff"/> +" id="m63986abc5f"/> - - + + - + @@ -1684,17 +1640,6 @@ z - - - - - - - @@ -1702,112 +1647,112 @@ L0 -3" id="mba139cba6e"/> M-3 0 L3 0 M0 3 -L0 -3" id="mba139cba6e"/> +L0 -3" id="m042afd644e"/> - - + + - +L9.07812 54.6875 +L18.1094 54.6875 +L18.1094 46.1875 +Q21.3438 51.125 25.7031 53.5625 +Q30.0781 56 35.7969 56 +Q45.2188 56 50.0469 50.1719 +Q54.8906 44.3438 54.8906 33.0156" id="BitstreamVeraSans-Roman-6e"/> +M44.2812 53.0781 +L44.2812 44.5781 +Q40.4844 46.5312 36.375 47.5 +Q32.2812 48.4844 27.875 48.4844 +Q21.1875 48.4844 17.8438 46.4375 +Q14.5 44.3906 14.5 40.2812 +Q14.5 37.1562 16.8906 35.375 +Q19.2812 33.5938 26.5156 31.9844 +L29.5938 31.2969 +Q39.1562 29.25 43.1875 25.5156 +Q47.2188 21.7812 47.2188 15.0938 +Q47.2188 7.46875 41.1875 3.01562 +Q35.1562 -1.42188 24.6094 -1.42188 +Q20.2188 -1.42188 15.4531 -0.5625 +Q10.6875 0.296875 5.42188 2 +L5.42188 11.2812 +Q10.4062 8.6875 15.2344 7.39062 +Q20.0625 6.10938 24.8125 6.10938 +Q31.1562 6.10938 34.5625 8.28125 +Q37.9844 10.4531 37.9844 14.4062 +Q37.9844 18.0625 35.5156 20.0156 +Q33.0625 21.9688 24.7031 23.7812 +L21.5781 24.5156 +Q13.2344 26.2656 9.51562 29.9062 +Q5.8125 33.5469 5.8125 39.8906 +Q5.8125 47.6094 11.2812 51.7969 +Q16.75 56 26.8125 56 +Q31.7812 56 36.1719 55.2656 +Q40.5781 54.5469 44.2812 53.0781" id="BitstreamVeraSans-Roman-73"/> + From 3de62de3ec4fc6d4a719ec10766e987ca2f00cbc Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 17 Aug 2011 09:56:59 -0400 Subject: [PATCH 085/214] Fix some crashes in the SVG backend found by @efiring. Also, add a Gouraud shading test to test framework so this doesn't fall through the cracks again --- lib/matplotlib/backends/backend_svg.py | 8 +- .../baseline_images/test_axes/pcolormesh.pdf | Bin 21046 -> 32312 bytes .../baseline_images/test_axes/pcolormesh.png | Bin 33662 -> 100037 bytes .../baseline_images/test_axes/pcolormesh.svg | 25848 +++++++++++++++- lib/matplotlib/tests/test_axes.py | 13 +- 5 files changed, 24242 insertions(+), 1627 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 44c84ee743a4..53e7346e2d70 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -641,12 +641,12 @@ def draw_gouraud_triangle(self, gc, points, colors, trans): x1=str(x1), y1=str(y1), x2=str(xb), y2=str(yb)) writer.element( 'stop', - offset=0, + offset='0', style=generate_css({'stop-color': rgb2hex(c), 'stop-opacity': str(c[-1])})) writer.element( 'stop', - offset=1, + offset='1', style=generate_css({'stop-color': rgb2hex(c), 'stop-opacity': "0"})) writer.end('linearGradient') @@ -788,7 +788,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): if color != '#000000': style['fill'] = color if gc.get_alpha() != 1.0: - style['opacity'] = gc.get_alpha() + style['opacity'] = str(gc.get_alpha()) if not ismath: font = text2path._get_font(prop) @@ -891,7 +891,7 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): if color != '#000000': style['fill'] = color if gc.get_alpha() != 1.0: - style['opacity'] = gc.get_alpha() + style['opacity'] = str(gc.get_alpha()) if not ismath: font = self._get_font(prop) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.pdf b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.pdf index e8c90f793a48496e9a2a08c3e06da9f80bf3b62a..0c8adad3bc251df8aa8ddeb869fe64dc6b7da683 100644 GIT binary patch delta 28306 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

M1NHb%ycl}5oY#^5yj)=jV+x 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.png b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.png index 1a04cd2c0577cebecb07243980be3362ce456e26..bc8a0153095cad5bff47f8fed3311850e2439eaa 100644 GIT binary patch literal 100037 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 {Uz3;rc?AJh@3=ABSxL{H` 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 H8} + - - - + diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 4bc58694416f..b028d6144dcf 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -525,18 +525,24 @@ def test_pcolormesh(): Zm = ma.masked_where(np.fabs(Qz) < 0.5*np.amax(Qz), Z) fig = plt.figure() - ax = fig.add_subplot(121) - ax.pcolormesh(Qx,Qz,Z, lw=0.5, edgecolors='k') + ax = fig.add_subplot(131) + ax.pcolormesh(Qx,Qz,Z, lw=0.5, edgecolors='k') ax.set_title('lw=0.5') ax.set_xticks([]) ax.set_yticks([]) - ax = fig.add_subplot(122) + ax = fig.add_subplot(132) ax.pcolormesh(Qx,Qz,Z, lw=3, edgecolors='k') ax.set_title('lw=3') ax.set_xticks([]) ax.set_yticks([]) + ax = fig.add_subplot(133) + ax.pcolormesh(Qx,Qz,Z, shading="gouraud") + ax.set_title('gouraud') + ax.set_xticks([]) + ax.set_yticks([]) + @image_comparison(baseline_images=['canonical']) def test_canonical(): @@ -619,6 +625,7 @@ def test_markevery_line(): ax.plot(x, y, '-+', markevery=(5, 20), label='mark every 5 starting at 10') ax.legend() + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False) From b62acc8668167e7298c74a828c0b6846fb3136ad Mon Sep 17 00:00:00 2001 From: Ben Root - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Wed, 17 Aug 2011 16:40:42 -0500 Subject: [PATCH 086/214] First draft of the v1.1.0 "What's New" section. Also fixed an error with stem() docs. --- doc/users/whats_new.rst | 128 +++++++++++++++++++++++++++++++++++++++- lib/matplotlib/axes.py | 10 ++-- 2 files changed, 131 insertions(+), 7 deletions(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index d2197942e292..58c1812d5428 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -7,6 +7,130 @@ What's new in matplotlib This page just covers the highlights -- for the full story, see the `CHANGELOG `_ + +.. _whats-new-1-1: + +new in matplotlib-1.1 +===================== + +Animation +--------- + +Ryan May invested significant effort to create a backend-independent +framework for creating animated figures. The :mod:`~matplotlib.animation` +module is intended to replace the difficult-to-understand, +backend-specific examples that has existed in the examples listing. + +This framework should be considered a beta feature for matplotlib, but +we highly encourage users to try it out and provide feedback. + +Tight Layout +------------ + +A frequent issue raised by users of matplotlib is the lack of a layout +engine to nicely space out elements of the plots. While we still adhere +to the philosphy of giving users complete control over the placement of +plot elements, a :mod:`~matplotlib.tight_layout` module was created to +address the most common layout issues. + +:mod:`~matplotlib.tight_layout` will adjust the spacing between subplots +so that the axis labels do not overlap with neighboring subplots. + +Need to acknowledge author + +Full IPython 0.11 compatibility +------------------------------- + +The `IPython `_ team has recently released v0.11 of +their interactive python shell. The matplotlib and IPython teams worked +to ensure that our packages work well together. This release of matplotlib +is fully compatible with ipython. + +Legend +------ + +Jae-Joon Lee has been working on revamping how plot legends are handled +in matplotlib. This has resulted in some immediate enhancements. First, +legends for :func:`~matplotlib.pyplot.stem` plots will now display +correctly. Second, the 'best' placement of a legend has been improved +in the presence of NaNs. + +mplot3d +------- + +In continuing the efforts to make 3D plotting in matplotlib just as easy +as 2D plotting, Ben Root has made several improvements to the +:mod:`~mpl_toolkits.mplot3d` module. + +* :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` has been + improved to bring the class towards feature-parity with regular + Axes objects + +* Documentation for the mplot3d module was significantly expanded. + +* Axis labels and orientation improved + +* Ticker offset display added + +* :func:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` + gains *zdir* and *offset* kwargs. + +* Most 3D plotting functions now support empty inputs + +Numerix support removed +----------------------- + +After more than two years of deprecation warnings, Numerix support has +now been completely removed from matplotlib. + +Markers +------- + +The list of available markers for :func:`~matplotlib.pyplot.plot` and +:func:`~matplotlib.pyplot.scatter` has now been merged. While they +were mostly similar, some markers existed for one function, but not +the other. This merge did result in a conflict for the 'd' diamond +marker. Now, 'd' will be interpreated to always mean "thin" diamond +while 'D' will mean "regular" diamond. + +Thanks to Michael Droettboom for this effort. + +Other improvements +------------------ + +* Unit support for polar axes and :func:`~matplotlib.axes.Axes.arrow` + +* :class:`~matplotlib.projections.polar.PolarAxes` gains + 'set_theta_direction', 'set_theta_zero_direction' and + 'set_theta_offset' functions. + +* Fixed error in argument handling for tri-functions such as + :func:`~matplotlib.pyplot.tripcolor` + +* 'axes.labelweight' parameter added to rcParams. + +* For :func:`~matplotlib.pyplot.imshow`, *interpolation='nearest'* will + now always perform an interpolation. A 'none' option has been added to + indicate no interpolation at all. + +* An error in the Hammer projection has been fixed. + +* *clabel* for :func:`~matplotlib.pyplot.contour` now accepts a callable. + Thanks to Daniel Hyams for the original patch! + +* Jae-Joon Lee added the :class:`~mpl_toolkits.axes_grid1.axes_divider.HBox` + and :class:`~mpl_toolkits.axes_grid1.axes_divider.VBox` classes. + +* Christoph Gohike improved memory usage in :func:`~matplotlib.pyplot.imshow`. + +* :func:`~matplotlib.pyplot.scatter` now accepts empty inputs. + +* The behavior for 'symlog' scale has been fixed, but this may result + in some minor changes to existing plots. + + +.. _whats-new-1-0: + new in matplotlib-1.0 ====================== @@ -53,7 +177,7 @@ talented developers for years. :func:`~matplotlib.pyplot.contourf` now handles interior masked regions, and the boundaries of line and filled contours coincide. -Additionally, he has contributed a new module `matplotlib.tri` and +Additionally, he has contributed a new module :mod:`~matplotlib.tri` and helper function :func:`~matplotlib.pyplot.triplot` for creating and plotting unstructured triangular grids. @@ -139,6 +263,8 @@ help from Jae-Joon Lee, Michael Droettboom, Christoph Gohlke and Michiel de Hoon. +.. _whats-new-0-99: + new in matplotlib-0.99 ====================== diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f1eab53fc514..b82e6e777184 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -4904,15 +4904,13 @@ def stem(self, x, y, linefmt='b-', markerfmt='bo', basefmt='r-', *baseline*). .. seealso:: + This `document `_ + for details. - `this document`__ - for details - :file:`examples/pylab_examples/stem_plot.py` - for a demo - - __ http://www.mathworks.com/access/helpdesk/help/techdoc/ref/stem.html + **Example:** + .. plot:: mpl_examples/pylab_examples/stem_plot.py """ remember_hold=self._hold if not self._hold: self.cla() From 307c06a15cef6c45484a88402dd5c90c27ba5a58 Mon Sep 17 00:00:00 2001 From: Miriam Sierig Date: Wed, 17 Aug 2011 23:39:35 -0500 Subject: [PATCH 087/214] remove deprecated ipython_directive (get it from ipython src) and releases dir --- lib/matplotlib/sphinxext/ipython_directive.py | 813 ------------------ release/osx/Makefile | 107 --- release/osx/README.txt | 98 --- release/osx/data/ReadMe.txt | 45 - release/osx/data/bdist.patch | 25 - release/osx/data/setup.cfg | 78 -- release/win32/Makefile | 112 --- release/win32/README.txt | 83 -- release/win32/data/mingw_path.sh | 57 -- release/win32/data/setup.cfg | 78 -- release/win32/data/setupwin.py | 12 - release/win32/data/setupwinegg.py | 15 - 12 files changed, 1523 deletions(-) delete mode 100644 lib/matplotlib/sphinxext/ipython_directive.py delete mode 100644 release/osx/Makefile delete mode 100644 release/osx/README.txt delete mode 100644 release/osx/data/ReadMe.txt delete mode 100644 release/osx/data/bdist.patch delete mode 100644 release/osx/data/setup.cfg delete mode 100644 release/win32/Makefile delete mode 100644 release/win32/README.txt delete mode 100644 release/win32/data/mingw_path.sh delete mode 100644 release/win32/data/setup.cfg delete mode 100644 release/win32/data/setupwin.py delete mode 100644 release/win32/data/setupwinegg.py diff --git a/lib/matplotlib/sphinxext/ipython_directive.py b/lib/matplotlib/sphinxext/ipython_directive.py deleted file mode 100644 index 543b41a9ad79..000000000000 --- a/lib/matplotlib/sphinxext/ipython_directive.py +++ /dev/null @@ -1,813 +0,0 @@ -# -*- coding: utf-8 -*- -"""Sphinx directive to support embedded IPython code. - -This directive allows pasting of entire interactive IPython sessions, prompts -and all, and their code will actually get re-executed at doc build time, with -all prompts renumbered sequentially. It also allows you to input code as a pure -python input by giving the argument python to the directive. The output looks -like an interactive ipython section. - -To enable this directive, simply list it in your Sphinx ``conf.py`` file -(making sure the directory where you placed it is visible to sphinx, as is -needed for all Sphinx directives). - -By default this directive assumes that your prompts are unchanged IPython ones, -but this can be customized. The configurable options that can be placed in -conf.py are - -ipython_savefig_dir: - The directory in which to save the figures. This is relative to the - Sphinx source directory. The default is `html_static_path`. -ipython_rgxin: - The compiled regular expression to denote the start of IPython input - lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You - shouldn't need to change this. -ipython_rgxout: - The compiled regular expression to denote the start of IPython output - lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You - shouldn't need to change this. -ipython_promptin: - The string to represent the IPython input prompt in the generated ReST. - The default is 'In [%d]:'. This expects that the line numbers are used - in the prompt. -ipython_promptout: - - The string to represent the IPython prompt in the generated ReST. The - default is 'Out [%d]:'. This expects that the line numbers are used - in the prompt. - -ToDo ----- - -- Turn the ad-hoc test() function into a real test suite. -- Break up ipython-specific functionality from matplotlib stuff into better - separated code. - -Authors -------- - -- John D Hunter: orignal author. -- Fernando Perez: refactoring, documentation, cleanups, port to 0.11. -- VáclavÃ… milauer : Prompt generalizations. -- Skipper Seabold, refactoring, cleanups, pure python addition -""" - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -# Stdlib -import cStringIO -import os -import re -import sys -import tempfile - -# To keep compatibility with various python versions -try: - from hashlib import md5 -except ImportError: - from md5 import md5 - -# Third-party -import matplotlib -import sphinx -from docutils.parsers.rst import directives -from docutils import nodes -from sphinx.util.compat import Directive - -matplotlib.use('Agg') - -# Our own -from IPython import Config, InteractiveShell -from IPython.core.profiledir import ProfileDir -from IPython.utils import io - -#----------------------------------------------------------------------------- -# Globals -#----------------------------------------------------------------------------- -# for tokenizing blocks -COMMENT, INPUT, OUTPUT = range(3) - -#----------------------------------------------------------------------------- -# Functions and class declarations -#----------------------------------------------------------------------------- -def block_parser(part, rgxin, rgxout, fmtin, fmtout): - """ - part is a string of ipython text, comprised of at most one - input, one ouput, comments, and blank lines. The block parser - parses the text into a list of:: - - blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...] - - where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and - data is, depending on the type of token:: - - COMMENT : the comment string - - INPUT: the (DECORATOR, INPUT_LINE, REST) where - DECORATOR: the input decorator (or None) - INPUT_LINE: the input as string (possibly multi-line) - REST : any stdout generated by the input line (not OUTPUT) - - - OUTPUT: the output string, possibly multi-line - """ - - block = [] - lines = part.split('\n') - N = len(lines) - i = 0 - decorator = None - while 1: - - if i==N: - # nothing left to parse -- the last line - break - - line = lines[i] - i += 1 - line_stripped = line.strip() - if line_stripped.startswith('#'): - block.append((COMMENT, line)) - continue - - if line_stripped.startswith('@'): - # we're assuming at most one decorator -- may need to - # rethink - decorator = line_stripped - continue - - # does this look like an input line? - matchin = rgxin.match(line) - if matchin: - lineno, inputline = int(matchin.group(1)), matchin.group(2) - - # the ....: continuation string - continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) - Nc = len(continuation) - # input lines can continue on for more than one line, if - # we have a '\' line continuation char or a function call - # echo line 'print'. The input line can only be - # terminated by the end of the block or an output line, so - # we parse out the rest of the input line if it is - # multiline as well as any echo text - - rest = [] - while i2: - if debug: - print '\n'.join(lines) - else: #NOTE: this raises some errors, what's it for? - #print 'INSERTING %d lines'%len(lines) - self.state_machine.insert_input( - lines, self.state_machine.input_lines.source(0)) - - text = '\n'.join(lines) - txtnode = nodes.literal_block(text, text) - txtnode['language'] = 'ipython' - #imgnode = nodes.image(figs) - - # cleanup - self.teardown() - - return []#, imgnode] - -# Enable as a proper Sphinx directive -def setup(app): - setup.app = app - - app.add_directive('ipython', IpythonDirective) - app.add_config_value('ipython_savefig_dir', None, True) - app.add_config_value('ipython_rgxin', - re.compile('In \[(\d+)\]:\s?(.*)\s*'), True) - app.add_config_value('ipython_rgxout', - re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True) - app.add_config_value('ipython_promptin', 'In [%d]:', True) - app.add_config_value('ipython_promptout', 'Out[%d]:', True) - - -# Simple smoke test, needs to be converted to a proper automatic test. -def test(): - - examples = [ - r""" -In [9]: pwd -Out[9]: '/home/jdhunter/py4science/book' - -In [10]: cd bookdata/ -/home/jdhunter/py4science/book/bookdata - -In [2]: from pylab import * - -In [2]: ion() - -In [3]: im = imread('stinkbug.png') - -@savefig mystinkbug.png width=4in -In [4]: imshow(im) -Out[4]: - -""", - r""" - -In [1]: x = 'hello world' - -# string methods can be -# used to alter the string -@doctest -In [2]: x.upper() -Out[2]: 'HELLO WORLD' - -@verbatim -In [3]: x.st -x.startswith x.strip -""", - r""" - -In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\ - .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' - -In [131]: print url.split('&') -['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv'] - -In [60]: import urllib - -""", - r"""\ - -In [133]: import numpy.random - -@suppress -In [134]: numpy.random.seed(2358) - -@doctest -In [135]: numpy.random.rand(10,2) -Out[135]: -array([[ 0.64524308, 0.59943846], - [ 0.47102322, 0.8715456 ], - [ 0.29370834, 0.74776844], - [ 0.99539577, 0.1313423 ], - [ 0.16250302, 0.21103583], - [ 0.81626524, 0.1312433 ], - [ 0.67338089, 0.72302393], - [ 0.7566368 , 0.07033696], - [ 0.22591016, 0.77731835], - [ 0.0072729 , 0.34273127]]) - -""", - - r""" -In [106]: print x -jdh - -In [109]: for i in range(10): - .....: print i - .....: - .....: -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -""", - - r""" - -In [144]: from pylab import * - -In [145]: ion() - -# use a semicolon to suppress the output -@savefig test_hist.png width=4in -In [151]: hist(np.random.randn(10000), 100); - - -@savefig test_plot.png width=4in -In [151]: plot(np.random.randn(10000), 'o'); - """, - - r""" -# use a semicolon to suppress the output -In [151]: plt.clf() - -@savefig plot_simple.png width=4in -In [151]: plot([1,2,3]) - -@savefig hist_simple.png width=4in -In [151]: hist(np.random.randn(10000), 100); - -""", - r""" -# update the current fig -In [151]: ylabel('number') - -In [152]: title('normal distribution') - - -@savefig hist_with_text.png -In [153]: grid(True) - - """, - ] - # skip local-file depending first example: - examples = examples[1:] - - #ipython_directive.DEBUG = True # dbg - #options = dict(suppress=True) # dbg - options = dict() - for example in examples: - content = example.split('\n') - ipython_directive('debug', arguments=None, options=options, - content=content, lineno=0, - content_offset=None, block_text=None, - state=None, state_machine=None, - ) - -# Run test suite as a script -if __name__=='__main__': - if not os.path.isdir('_static'): - os.mkdir('_static') - test() - print 'All OK? Check figures in _static/' diff --git a/release/osx/Makefile b/release/osx/Makefile deleted file mode 100644 index 88f03ab9a30a..000000000000 --- a/release/osx/Makefile +++ /dev/null @@ -1,107 +0,0 @@ -PYVERSION=2.6 -PYTHON=python${PYVERSION} -SRCDIR=${PWD} -ZLIBVERSION=1.2.3 -PNGVERSION=1.2.33 -FREETYPEVERSION=2.3.7 -MPLVERSION=1.0 -BDISTMPKGVERSION=0.4.4 -MPLSRC=matplotlib-${MPLVERSION} -MACOSX_DEPLOYMENT_TARGET=10.4 - -## You shouldn't need to configure past this point - -CFLAGS="-Os -arch ppc -arch i386 -I${SRCDIR}/zlib-${ZLIBVERSION} -I${SRCDIR}/libpng-${PNGVERSION} -I${SRCDIR}/freetype-${FREETYPEVERSION}/include" - -LDFLAGS="-arch ppc -arch i386 -L${SRCDIR}/zlib-${ZLIBVERSION} -L${SRCDIR}/libpng-${PNGVERSION} -L${SRCDIR}/freetype-${FREETYPEVERSION}" - -CFLAGS_ZLIB="-arch i386 -arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk" -LDFLAGS_ZLIB="-arch i386 -arch ppc -syslibroot,/Developer/SDKs/MacOSX10.4u.sdk" - -CFLAGS_DEPS="-arch i386 -arch ppc -I${SRCDIR}/zlib-${ZLIBVERSION} -isysroot /Developer/SDKs/MacOSX10.4u.sdk" -LDFLAGS_DEPS="-arch i386 -arch ppc -L${SRCDIR}/zlib-${ZLIBVERSION} -syslibroot,/Developer/SDKs/MacOSX10.4u.sdk" - -clean: - rm -rf zlib-${ZLIBVERSION}.tar.gz libpng-${PNGVERSION}.tar.bz2 \ - freetype-${FREETYPEVERSION}.tar.bz2 bdist_mpkg-${BDISTMPKGVERSION}.tar.gz \ - bdist_mpkg-${BDISTMPKGVERSION} \ - zlib-${ZLIBVERSION} libpng-${PNGVERSION} freetype-${FREETYPEVERSION} \ - matplotlib-${MPLVERSION} *~ - -fetch: - curl -LO http://www.zlib.net/zlib-${ZLIBVERSION}.tar.gz &&\ - curl -LO http://internap.dl.sourceforge.net/sourceforge/libpng/libpng-${PNGVERSION}.tar.bz2 &&\ - curl -LO http://download.savannah.gnu.org/releases/freetype/freetype-${FREETYPEVERSION}.tar.bz2&&\ - curl -LO http://pypi.python.org/packages/source/b/bdist_mpkg/bdist_mpkg-${BDISTMPKGVERSION}.tar.gz&&\ - tar xvfz bdist_mpkg-${BDISTMPKGVERSION}.tar.gz &&\ - echo "You need to install bdist_mpkg-${BDISTMPKGVERSION} now" - - - -zlib: - unset PKG_CONFIG_PATH &&\ - rm -rf zlib-${ZLIBVERSION} &&\ - tar xvfz zlib-${ZLIBVERSION}.tar.gz &&\ - cd zlib-${ZLIBVERSION} &&\ - export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} &&\ - export CFLAGS=${CFLAGS_DEPS} &&\ - export LDFLAGS=${LDFLAGS_DEPS} &&\ - ./configure &&\ - MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} CFLAGS=${CFLAGS_ZLIB} LDFLAGS=${LDFLAGS_ZLIB} make -j3&& \ - unset MACOSX_DEPLOYMENT_TARGET - -png: zlib - unset PKG_CONFIG_PATH &&\ - rm -rf libpng-${PNGVERSION} &&\ - tar xvfj libpng-${PNGVERSION}.tar.bz2 - cd libpng-${PNGVERSION} &&\ - export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} &&\ - export CFLAGS=${CFLAGS_DEPS} &&\ - export LDFLAGS=${LDFLAGS_DEPS} &&\ - ./configure --disable-dependency-tracking &&\ - make -j3 &&\ - cp .libs/libpng.a . &&\ - unset MACOSX_DEPLOYMENT_TARGET - - -freetype: zlib - unset PKG_CONFIG_PATH &&\ - rm -rf ${FREETYPEVERSION} &&\ - tar xvfj freetype-${FREETYPEVERSION}.tar.bz2 &&\ - cd freetype-${FREETYPEVERSION} &&\ - export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} &&\ - export CFLAGS=${CFLAGS_DEPS} &&\ - export LDFLAGS=${LDFLAGS_DEPS} &&\ - ./configure &&\ - make -j3 &&\ - cp objs/.libs/libfreetype.a . &&\ - unset MACOSX_DEPLOYMENT_TARGET - -deps: - make zlib png freetype - -installers: - unset PKG_CONFIG_PATH &&\ - tar xvfz matplotlib-${MPLVERSION}.tar.gz && \ - cd ${MPLSRC} && \ - rm -rf build && \ - cp ../data/setup.cfg ../data/ReadMe.txt . &&\ - export CFLAGS=${CFLAGS} &&\ - export LDFLAGS=${LDFLAGS} &&\ - /Library/Frameworks/Python.framework/Versions/${PYVERSION}/bin/bdist_mpkg --readme=ReadMe.txt &&\ - hdiutil create -srcdir dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx10.5.mpkg dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx10.5.dmg &&\ - ${PYTHON} setupegg.py bdist_egg - -upload: - rm -rf upload &&\ - mkdir upload &&\ - cp matplotlib-${MPLVERSION}.tar.gz upload/ &&\ - cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}_r0-py${PYVERSION}-macosx-10.3-fat.egg upload/matplotlib-${MPLVERSION}-macosx-py${PYVERSION}.egg &&\ - cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}-py${PYVERSION}-macosx10.5.zip upload/matplotlib-${MPLVERSION}-py${PYVERSION}-mpkg.zip&&\ - scp upload/* jdh2358@frs.sourceforge.net:uploads/ - -all: - make clean fetch deps installers upload - - - diff --git a/release/osx/README.txt b/release/osx/README.txt deleted file mode 100644 index de5e19edc672..000000000000 --- a/release/osx/README.txt +++ /dev/null @@ -1,98 +0,0 @@ -Building binary releases of OS X - -Included here is everything to build a binary package installer for OS -X - -Dir Contents -------------- - -* :file:`bdist_mkpg` - the distutils.extension to build Installer.app - mpkg installers. - -* :file:`data` - some config files and patches needed for the build - -* :file:`*.tar.gz` - the bdist_mkpg, zlib, png, freetype and mpl - tarballs - -* :file:`Makefile` - all the build commands - -How to build --------------- - -* You need a python framework build, numpy and wxpython to build the - mpl installers (wx requires this and we need wx to build the wxagg - extension). I recommend building python from src as a framework build:: - - ./configure --enable-universalsdk --enable-framework - sudo make install - - and build numpy from src too since the 2.5 numpy installer doesn't work - with a python built from src:: - - sudo python setup.py install - - you can use the pre-built installer for wx:: - - http://downloads.sourceforge.net/project/wxpython/wxPython/2.8.10.1/wxPython2.8-osx-unicode-2.8.10.1-universal-py2.6.dmg?use_mirror=voxel - -* You need to make sure to unset PKG_CONFIG_PATH to make sure the - static linking below is respected. Otherwise the mpl build script - will dynamically link using the libs from pkgconfig if you have this - configured on your box:: - - unset PKG_CONFIG_PATH - -* OPTIONAL: edit :file:`Makefile` so that the *VERSION variables point - to the latest zlib, png, freetype - -* First fetch all the dependencies and patch bdist_mpkg for OSX 10.5. - You can do this automatically in one step with:: - - make fetch - -* install the patched bdist_mpkg, that the fetch step just created:: - - cd bdist_mpkg-0.4.4 - sudo python setup.py install - -* build the dependencies:: - - make deps - -* copy over the latest mpl *.tar.gz tarball to this directory, update - the MPLVERSION in the Makefile:: - - cp /path/to/mpl/matplotlib.0.98.5.tar.gz . - -* build the mkpg binary and egg - - make installers - - The mpkg and egg binaries will reside in :file:`matplotlib-VERSION/dist` - -Crib sheet -------------- - -Build the dependencies:: - - cd release/osx/ - unset PKG_CONFIG_PATH - make fetch - cd bdist_mpkg-0.4.4 - sudo python setup.py install - cd .. - make deps - -Build the mpl sdist:: - - cd ../.. - python setup.py sdist - mv dist/matplotlib-0.98.6.tar.gz release/osx/ - -Set the version number in the Makefile to 0.98.6 and build the -installers :: - - cd release/osx - make installers - - diff --git a/release/osx/data/ReadMe.txt b/release/osx/data/ReadMe.txt deleted file mode 100644 index 318ee55f43c0..000000000000 --- a/release/osx/data/ReadMe.txt +++ /dev/null @@ -1,45 +0,0 @@ -matplotlib for MacOS X 10.3.9 or later and Python 2.5 and Python 2.6 - -matplotlib is a python 2D plotting library which produces publication -quality figures in a variety of hardcopy formats and interactive -environments across platforms. matplotlib can be used in python -scripts, the python and ipython shell (ala matlab or mathematica), web -application servers, and various graphical user interface toolkits. - -Home page: - -Before running matplotlib, you must install numpy. Binary installers -for all these packages are available here: - - . - -*** Back Ends *** - -You may use TkAgg or WXAgg back ends; Qt and GTK support is not -provided in this package. By default this matplotlib uses TkAgg -because Tcl/Tk is included with MacOS X. - -If you wish to use WXAgg then: -* Install wxPython from: - . -* Configure a matplotlibrc file, as described below. - -For TkAgg you may use Apple's built-in Tcl/Tk or install your own 8.4.x - -*** Configuring a matplotlibrc file *** - -If you wish to change any matplotlib settings, create a file: - ~/.matplotlib/matplotlibrc - - -that contains at least the following information. The values shown are -the defaults in the internal matplotlibrc file; change them as you see -fit: - -# the default backend; one of GTK GTKAgg GTKCairo FltkAgg QtAgg TkAgg WXAgg -# Agg Cairo GD GDK Paint PS PDF SVG Template -backend : TkAgg -interactive : False # see http://matplotlib.sourceforge.net/interactive.html - -See also - diff --git a/release/osx/data/bdist.patch b/release/osx/data/bdist.patch deleted file mode 100644 index 0a802ab4c81a..000000000000 --- a/release/osx/data/bdist.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -rNu bdist_mpkg-0.4.3/bdist_mpkg/tools.py bdist_mpkg-0.4.3.leopard/bdist_mpkg/tools.py ---- bdist_mpkg-0.4.3/bdist_mpkg/tools.py 2006-07-09 00:39:00.000000000 -0400 -+++ bdist_mpkg-0.4.3.leopard/bdist_mpkg/tools.py 2008-08-21 07:43:35.000000000 -0400 -@@ -79,15 +79,12 @@ - yield os.path.join(root, fn) - - def get_gid(name, _cache={}): -- if not _cache: -- for line in os.popen('/usr/bin/nidump group .'): -- fields = line.split(':') -- if len(fields) >= 3: -- _cache[fields[0]] = int(fields[2]) -- try: -- return _cache[name] -- except KeyError: -- raise ValueError('group %s not found' % (name,)) -+ for line in os.popen("dscl . -read /Groups/" + name + " PrimaryGroupID"): -+ fields = [f.strip() for f in line.split(':')] -+ if fields[0] == "PrimaryGroupID": -+ return fields[1] -+ -+ raise ValueError('group %s not found' % (name,)) - - def find_root(path, base='/'): - """ diff --git a/release/osx/data/setup.cfg b/release/osx/data/setup.cfg deleted file mode 100644 index c4f9682284c8..000000000000 --- a/release/osx/data/setup.cfg +++ /dev/null @@ -1,78 +0,0 @@ -# Rename this file to setup.cfg to modify matplotlib's -# build options. - -[egg_info] - -[status] -# To suppress display of the dependencies and their versions -# at the top of the build log, uncomment the following line: -#suppress = True -# -# Uncomment to insert lots of diagnostic prints in extension code -#verbose = True - -[provide_packages] -# By default, matplotlib checks for a few dependencies and -# installs them if missing. This feature can be turned off -# by uncommenting the following lines. Acceptible values are: -# True: install, overwrite an existing installation -# False: do not install -# auto: install only if the package is unavailable. This -# is the default behavior -# -## Date/timezone support: -pytz = True -dateutil = True - - -[gui_support] -# Matplotlib supports multiple GUI toolkits, including Cocoa, -# GTK, Fltk, MacOSX, Qt, Qt4, Tk, and WX. Support for many of -# these toolkits requires AGG, the Anti-Grain Geometry library, -# which is provided by matplotlib and built by default. -# -# Some backends are written in pure Python, and others require -# extension code to be compiled. By default, matplotlib checks -# for these GUI toolkits during installation and, if present, -# compiles the required extensions to support the toolkit. GTK -# support requires the GTK runtime environment and PyGTK. Wx -# support requires wxWidgets and wxPython. Tk support requires -# Tk and Tkinter. The other GUI toolkits do not require any -# extension code, and can be used as long as the libraries are -# installed on your system. -# -# You can uncomment any the following lines if you know you do -# not want to use the GUI toolkit. Acceptible values are: -# True: build the extension. Exits with a warning if the -# required dependencies are not available -# False: do not build the extension -# auto: build if the required dependencies are available, -# otherwise skip silently. This is the default -# behavior -# -#gtk = False -#gtkagg = False -tkagg = True -wxagg = True -macosx = True - -[rc_options] -# User-configurable options -# -# Default backend, one of: Agg, Cairo, CocoaAgg, GTK, GTKAgg, GTKCairo, -# FltkAgg, MacOSX, Pdf, Ps, QtAgg, Qt4Agg, SVG, TkAgg, WX, WXAgg. -# -# The Agg, Ps, Pdf and SVG backends do not require external -# dependencies. Do not choose GTK, GTKAgg, GTKCairo, MacOSX, TkAgg or WXAgg -# if you have disabled the relevent extension modules. Agg will be used -# by default. -# -backend = TkAgg -# -# The numerix module was historically used to provide -# compatibility between the Numeric, numarray, and NumPy array -# packages. Now that NumPy has emerge as the universal array -# package for python, numerix is not really necessary and is -# maintained to provide backward compatibility. Do not change -# this unless you have a compelling reason to do so. -#numerix = numpy diff --git a/release/win32/Makefile b/release/win32/Makefile deleted file mode 100644 index 2257b33511b6..000000000000 --- a/release/win32/Makefile +++ /dev/null @@ -1,112 +0,0 @@ -PYDIR = C:/Python25 -PYTHON = ${PYDIR}/python.exe -SRCDIR = ${PWD} -WINSRCDIR = `${PWD}/data/mingw_path.sh ${PWD}` -ZLIBVERSION = 1.2.3 -PNGVERSION = 1.2.36 -FREETYPEVERSION = 2.3.9 -TCLTKVERSION = 8.5.7 -MPLVERSION = 0.99.0.rc1 - -## You shouldn't need to configure past this point - -CFLAGS = -Os -D_ftime=ftime64 -DPNG_NO_READ_tIME -DPNG_NO_WRITE_tIME - - -PY_INCLUDE = "${WINSRCDIR}\\zlib-${ZLIBVERSION};${WINSRCDIR}/libpng-${PNGVERSION};${WINSRCDIR}/freetype-${FREETYPEVERSION}/include;${WINSRCDIR}/tcl${TCLTKVERSION}/generic;${WINSRCDIR}/tcl${TCLTKVERSION}/win;${WINSRCDIR}/tk${TCLTKVERSION}/generic;${WINSRCDIR}/tk${TCLTKVERSION}/win;${WINSRCDIR}/tk${TCLTKVERSION}/xlib" - -PY_LINKER = "${WINSRCDIR}/zlib-${ZLIBVERSION};${WINSRCDIR}/libpng-${PNGVERSION};${WINSRCDIR}/freetype-${FREETYPEVERSION}" - -clean: - rm -rf zlib-${ZLIBVERSION}.tar.gz libpng-${PNGVERSION}.tar.bz2 \ - freetype-${FREETYPEVERSION}.tar.bz2 \ - tcl${TCLTKVERSION}-src.tar.gz tk${TCLTKVERSION}-src.tar.gz \ - zlib-${ZLIBVERSION} libpng-${PNGVERSION} freetype-${FREETYPEVERSION} \ - tcl${TCLTKVERSION} tk${TCLTKVERSION} \ - matplotlib-${MPLVERSION} *~ - -fetch_deps: - wget http://www.zlib.net/zlib-${ZLIBVERSION}.tar.gz - wget http://prdownloads.sourceforge.net/libpng/libpng-${PNGVERSION}.tar.bz2 - wget http://prdownloads.sourceforge.net/freetype/freetype-2.3.9.tar.bz2 - wget http://prdownloads.sourceforge.net/tcl/tcl${TCLTKVERSION}-src.tar.gz - wget http://prdownloads.sourceforge.net/tcl/tk${TCLTKVERSION}-src.tar.gz - -zlib: - rm -rf zlib-${ZLIBVERSION} - tar xvfz zlib-${ZLIBVERSION}.tar.gz - cd zlib-${ZLIBVERSION} &&\ - export CFLAGS="${CFLAGS}" &&\ - ./configure &&\ - make -j3 - -# for reasons not clear to me, part of png compilation was failing -# because it could not find zlib.h, even with the CFLAGS which point -# to it and even with tryting to pass --includedir to configure. So I -# manually copy the zlib *.h files into the png dir - JDH -png: zlib - rm -rf libpng-${PNGVERSION} - tar xvfj libpng-${PNGVERSION}.tar.bz2 - cd libpng-${PNGVERSION} &&\ - cp ${SRCDIR}/zlib-${ZLIBVERSION}/*.h . && \ - export CFLAGS="${CFLAGS} -I${SRCDIR}/zlib-${ZLIBVERSION}" &&\ - export LDFLAGS="-L${SRCDIR}/zlib-${ZLIBVERSION}" &&\ - ./configure --disable-shared &&\ - make -j3 &&\ - cp .libs/libpng.a . - -freetype: - rm -rf freetype-${FREETYPEVERSION} - tar xvfj freetype-${FREETYPEVERSION}.tar.bz2 - cd freetype-${FREETYPEVERSION} &&\ - GNUMAKE=mingw32-make ./configure --disable-shared &&\ - cp builds/win32/w32-mingw32.mk config.mk &&\ - mingw32-make -j3 &&\ - cp objs/libfreetype.a . - -freetype_hide: - rm -rf freetype-${FREETYPEVERSION} - tar xvfj freetype-${FREETYPEVERSION}.tar.bz2 - cd freetype-${FREETYPEVERSION} &&\ - export CFLAGS=${CFLAGS} &&\ - ./configure --disable-shared &&\ - cp builds/win32/w32-mingw32.mk config.mk &&\ - make -j3 &&\ - cp objs/libfreetype.a . - -tcltk: - rm -rf tcl${TCLTKVERSION} - rm -rf tk${TCLTKVERSION} - tar xvfz tcl${TCLTKVERSION}-src.tar.gz - tar xvfz tk${TCLTKVERSION}-src.tar.gz - -dependencies: png freetype tcltk - -installers: - rm -rf matplotlib-${MPLVERSION} - tar xvzf matplotlib-${MPLVERSION}.tar.gz - cd matplotlib-${MPLVERSION} &&\ - rm -rf build &&\ - cp ../data/setup*.* . &&\ - export CFLAGS="${CFLAGS}" &&\ - ${PYTHON} setupwin.py build_ext -c mingw32 -I ${PY_INCLUDE} -L ${PY_LINKER} bdist_wininst &&\ - ${PYTHON} setupwinegg.py build_ext -c mingw32 -I ${PY_INCLUDE} -L ${PY_LINKER} bdist_egg - - -inplace: - #rm -rf matplotlib-${MPLVERSION} - #tar xvzf matplotlib-${MPLVERSION}.tar.gz - cd matplotlib-${MPLVERSION} &&\ - rm -rf build lib/matplotlib/*.pyd lib/matplotlib/*.pyc lib/matplotlib/backends/*.pyd lib/matplotlib/backends/*.pyc &&\ - cp ../data/setup*.* . &&\ - ${PYTHON} setup.py build_ext -c mingw32 -I ${PY_INCLUDE} -L ${PY_LINKER} --inplace - cd matplotlib-${MPLVERSION}/lib &&\ - ${PYTHON} -c 'import matplotlib; matplotlib.use("Agg"); from pylab import *; print matplotlib.__file__; plot([1,2,3]); savefig("test.png")' - -test_png: - ${PYTHON} -c 'import matplotlib; matplotlib.use("Agg"); from pylab import *; print matplotlib.__file__; plot([1,2,3]); savefig("test.png")' - -test_plot: - ${PYTHON} -c 'import matplotlib; from pylab import *; print matplotlib.__file__; plot([1,2,3]); show()' - -all: fetch_deps dependencies installers diff --git a/release/win32/README.txt b/release/win32/README.txt deleted file mode 100644 index 77fb956a748b..000000000000 --- a/release/win32/README.txt +++ /dev/null @@ -1,83 +0,0 @@ -Building binary releases of WIN32 - -Included here is everything to build a binary package installer for WIN32 using MinGW - -MinGW Requirements -------------- - -* Install MinGW using the "Automated MinGW Installer":: - - (tested with MinGW-5.1.4.exe) - http://sourceforge.net/project/showfiles.php?group_id=2435&package_id=240780 - - -* Install "MSYS Base System":: - - (tested with MSYS-1.0.10.exe) - http://sourceforge.net/project/showfiles.php?group_id=2435&package_id=24963 - -* Install wget from "mingwPORT":: - - (tested with wget-1.9.1-mingwPORT.tar.bz2) - http://sourceforge.net/project/showfiles.php?group_id=2435&package_id=233332 - NOTE: Uncompress and copy the "wget.exe" file to "C:\MingW\bin\" - - -* Test your installation. After installing the above, open MSYS and - check your install by doing:: - - > gcc --version - > g++ --version - - If you don't have g++, try running the mingw exe installer again, - and you will be prompted for additional compilers to install. - Select c++ and you are off to the races. - - Make sure setuptools are installed:: - - > /c/python26/python - >>> import setuptools - - If not, grab the latest ez_setup.py and install it:: - - > wget http://peak.telecommunity.com/dist/ez_setup.py - > /c/python26/python ez_setup.py - -Dir Contents -------------- - -* :file:`data` - some config files and patches needed for the build - -* :file:`Makefile` - all the build commands - -How to build --------------- - -* Edit the variables as needed in :file:`Makefile` - -* Open a msys shell from:: - - All Programs -> MinGW -> MSYS -> msys - -* First fetch all the dependencies:: - - make fetch_deps - -* build the dependencies:: - - make dependencies - -* copy over the latest mpl *.tar.gz tarball to this directory. You - can create the source distribution file with :: - - > /c/Python26/python sdist --formats=gztar - - and then copy the dist/matplotlib.VERSION.tar.gz file into the - directory alongside the Makefile. Update the MPLVERSION in the - Makefile:: - -* build the wininst binary and egg:: - - make installers - - The wininst and egg binaries will reside in :file:`matplotlib-VERSION/dist` diff --git a/release/win32/data/mingw_path.sh b/release/win32/data/mingw_path.sh deleted file mode 100644 index 1627998c51f1..000000000000 --- a/release/win32/data/mingw_path.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -# This script will convert a UNIX path to a Win32 native path -UPATH=$1 -if test "$UPATH" = ""; then - echo EMPTY - exit 1 -fi -#echo "INPUT IS \"$UPATH\"" >&2 -if [ -d "$UPATH" ] -then - cd "$UPATH" - WPATH=`pwd -W` -else - # cd up to parent directories until we find - # one that exists. Loop ends at "/". - dpart=`dirname "$UPATH"` - #echo "dpart starts as \"$dpart\"" >&2 - while [ ! -d "$dpart" ] - do - dpart=`dirname "$dpart"` - #echo "dpart is \"$dpart\"" >&2 - done - #echo "dpart ends as \"$dpart\"" >&2 - - if [ "$dpart" != "." ] - then - dstart=`expr length "$dpart"` - # If the last character in dpart is not "/", - # then advance dstart by one index. This - # avoids two dir seperators in the result. - last=`expr length "$dpart"` - last=`expr $last - 1` - last=${dpart:$last:1} - #echo "last is \"$last\"" >&2 - if [ "$last" != "/" ] - then - dstart=`expr $dstart + 1` - fi - dend=`expr length "$UPATH"` - dlen=`expr $dend - $dstart` - #echo "UPATH is \"$UPATH\"" >&2 - #echo "dstart is $dstart, dend is $dend, dlen is $dlen" >&2 - bpart=${UPATH:$dstart:$dend} - dpart=`cd "$dpart" ; pwd -W` - #echo "dpart \"$dpart\"" >&2 - #echo "bpart \"$bpart\"" >&2 - else - dpart=`pwd -W` - bpart=$UPATH - fi - WPATH=${dpart}/${bpart} -fi -#echo "OUTPUT IS \"$WPATH\"" >&2 -echo $WPATH -exit 0 - diff --git a/release/win32/data/setup.cfg b/release/win32/data/setup.cfg deleted file mode 100644 index 03fecb25d0a0..000000000000 --- a/release/win32/data/setup.cfg +++ /dev/null @@ -1,78 +0,0 @@ -# Rename this file to setup.cfg to modify matplotlib's -# build options. - -[egg_info] - -[status] -# To suppress display of the dependencies and their versions -# at the top of the build log, uncomment the following line: -#suppress = True -# -# Uncomment to insert lots of diagnostic prints in extension code -#verbose = True - -[provide_packages] -# By default, matplotlib checks for a few dependencies and -# installs them if missing. This feature can be turned off -# by uncommenting the following lines. Acceptible values are: -# True: install, overwrite an existing installation -# False: do not install -# auto: install only if the package is unavailable. This -# is the default behavior -# -## Date/timezone support: -pytz = True -dateutil = True - - -[gui_support] -# Matplotlib supports multiple GUI toolkits, including Cocoa, -# GTK, Fltk, MacOSX, Qt, Qt4, Tk, and WX. Support for many of -# these toolkits requires AGG, the Anti-Grain Geometry library, -# which is provided by matplotlib and built by default. -# -# Some backends are written in pure Python, and others require -# extension code to be compiled. By default, matplotlib checks -# for these GUI toolkits during installation and, if present, -# compiles the required extensions to support the toolkit. GTK -# support requires the GTK runtime environment and PyGTK. Wx -# support requires wxWidgets and wxPython. Tk support requires -# Tk and Tkinter. The other GUI toolkits do not require any -# extension code, and can be used as long as the libraries are -# installed on your system. -# -# You can uncomment any the following lines if you know you do -# not want to use the GUI toolkit. Acceptible values are: -# True: build the extension. Exits with a warning if the -# required dependencies are not available -# False: do not build the extension -# auto: build if the required dependencies are available, -# otherwise skip silently. This is the default -# behavior -# -gtk = False -gtkagg = False -tkagg = True -wxagg = False -macosx = False - -[rc_options] -# User-configurable options -# -# Default backend, one of: Agg, Cairo, CocoaAgg, GTK, GTKAgg, GTKCairo, -# FltkAgg, MacOSX, Pdf, Ps, QtAgg, Qt4Agg, SVG, TkAgg, WX, WXAgg. -# -# The Agg, Ps, Pdf and SVG backends do not require external -# dependencies. Do not choose GTK, GTKAgg, GTKCairo, MacOSX, TkAgg or WXAgg -# if you have disabled the relevent extension modules. Agg will be used -# by default. -# -backend = TkAgg -# -# The numerix module was historically used to provide -# compatibility between the Numeric, numarray, and NumPy array -# packages. Now that NumPy has emerge as the universal array -# package for python, numerix is not really necessary and is -# maintained to provide backward compatibility. Do not change -# this unless you have a compelling reason to do so. -#numerix = numpy diff --git a/release/win32/data/setupwin.py b/release/win32/data/setupwin.py deleted file mode 100644 index 01bffae2c4c5..000000000000 --- a/release/win32/data/setupwin.py +++ /dev/null @@ -1,12 +0,0 @@ -from distutils import cygwinccompiler - -try: - # Python 2.6 - # Replace the msvcr func to return an [] - cygwinccompiler.get_msvcr - cygwinccompiler.get_msvcr = lambda: [] - -except AttributeError: - pass - -execfile('setup.py') diff --git a/release/win32/data/setupwinegg.py b/release/win32/data/setupwinegg.py deleted file mode 100644 index d12c9b3ff119..000000000000 --- a/release/win32/data/setupwinegg.py +++ /dev/null @@ -1,15 +0,0 @@ -from distutils import cygwinccompiler - -try: - # Python 2.6 - # Replace the msvcr func to return an empty list - cygwinccompiler.get_msvcr - cygwinccompiler.get_msvcr = lambda: [] - -except AttributeError: - pass - -from setuptools import setup -execfile('setup.py', - {'additional_params' : - {'namespace_packages' : ['mpl_toolkits']}}) From fcebc2338ad730098520c866122061eefd866641 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Wed, 17 Aug 2011 15:41:09 +0900 Subject: [PATCH 088/214] Change api of Axes.get_tightbbox and add an optional keyword parameter *call_axes_locator* --- CHANGELOG | 3 +++ lib/matplotlib/axes.py | 13 +++++++++---- lib/mpl_toolkits/axes_grid1/axes_size.py | 7 +++---- lib/mpl_toolkits/axes_grid1/parasite_axes.py | 19 ++++++++++--------- lib/mpl_toolkits/axisartist/axislines.py | 18 +++++++++--------- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a46c6bdf3a53..b13b6496b253 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2011-08-18 Change api of Axes.get_tightbbox and add an optional + keyword parameter *call_axes_locator*. - JJL + 2011-07-15 The set of markers available in the plot() and scatter() commands has been unified. In general, this gives more options to both than were previously available, however, diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index f1eab53fc514..6904d5786130 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -5770,7 +5770,7 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None, marker_obj.get_transform()) if not marker_obj.is_filled(): edgecolors = 'face' - + collection = mcoll.PathCollection( (path,), scales, facecolors = colors, @@ -8242,11 +8242,16 @@ def matshow(self, Z, **kwargs): integer=True)) return im - - def get_tightbbox(self, renderer): + def get_tightbbox(self, renderer, call_axes_locator=True): """ return the tight bounding box of the axes. The dimension of the Bbox in canvas coordinate. + + If call_axes_locator is False, it does not call the + _axes_locator attribute, which is necessary to get the correct + bounding box. call_axes_locator==False can be used if the + caller is only intereted in the relative size of the tightbbox + compared to the axes bbox. """ artists = [] @@ -8256,7 +8261,7 @@ def get_tightbbox(self, renderer): return None locator = self.get_axes_locator() - if locator: + if locator and call_axes_locator: pos = locator(self, renderer) self.apply_aspect(pos) else: diff --git a/lib/mpl_toolkits/axes_grid1/axes_size.py b/lib/mpl_toolkits/axes_grid1/axes_size.py index 0eda2c822335..6c35e1440b74 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_size.py +++ b/lib/mpl_toolkits/axes_grid1/axes_size.py @@ -270,13 +270,13 @@ def _get_top(tight_bbox, axes_bbox): top=_get_top) del _get_left, _get_right, _get_bottom, _get_top - + def __init__(self, ax, direction): if isinstance(ax, Axes): self._ax_list = [ax] else: self._ax_list = ax - + try: self._get_func = self._get_func_map[direction] except KeyError: @@ -284,8 +284,7 @@ def __init__(self, ax, direction): raise def __call__(self, renderer): - vl = [self._get_func(ax.get_tightbbox(renderer), + vl = [self._get_func(ax.get_tightbbox(renderer, False), ax.bbox) for ax in self._ax_list] return max(vl) - diff --git a/lib/mpl_toolkits/axes_grid1/parasite_axes.py b/lib/mpl_toolkits/axes_grid1/parasite_axes.py index 39a7d981020f..b13de8f69a25 100644 --- a/lib/mpl_toolkits/axes_grid1/parasite_axes.py +++ b/lib/mpl_toolkits/axes_grid1/parasite_axes.py @@ -208,7 +208,7 @@ def parasite_axes_auxtrans_class_factory(axes_class=None): parasite_axes_class = parasite_axes_class_factory(axes_class) else: parasite_axes_class = axes_class - + new_class = _parasite_axes_auxtrans_classes.get(parasite_axes_class) if new_class is None: import new @@ -319,7 +319,7 @@ def twinx(self, axes_class=None): axes_class = self._get_base_axes() parasite_axes_class = parasite_axes_class_factory(axes_class) - + ax2 = parasite_axes_class(self, sharex=self, frameon=False) self.parasites.append(ax2) @@ -353,7 +353,7 @@ def twiny(self, axes_class=None): axes_class = self._get_base_axes() parasite_axes_class = parasite_axes_class_factory(axes_class) - + ax2 = parasite_axes_class(self, sharey=self, frameon=False) self.parasites.append(ax2) @@ -386,7 +386,7 @@ def twin(self, aux_trans=None, axes_class=None): axes_class = self._get_base_axes() parasite_axes_auxtrans_class = parasite_axes_auxtrans_class_factory(axes_class) - + if aux_trans is None: ax2 = parasite_axes_auxtrans_class(self, mtransforms.IdentityTransform(), viewlim_mode="equal", @@ -436,23 +436,24 @@ def twin(self, aux_trans=None, axes_class=None): return ax2 - def get_tightbbox(self, renderer): + def get_tightbbox(self, renderer, call_axes_locator=True): - bbs = [ax.get_tightbbox(renderer) for ax in self.parasites] + bbs = [ax.get_tightbbox(renderer, call_axes_locator) \ + for ax in self.parasites] get_tightbbox = self._get_base_axes_attr("get_tightbbox") - bbs.append(get_tightbbox(self, renderer)) + bbs.append(get_tightbbox(self, renderer, call_axes_locator)) _bbox = Bbox.union([b for b in bbs if b.width!=0 or b.height!=0]) return _bbox - + _host_axes_classes = {} def host_axes_class_factory(axes_class=None): if axes_class is None: axes_class = Axes - + new_class = _host_axes_classes.get(axes_class) if new_class is None: import new diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index 1c9f384f2a74..463752e63f61 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -378,7 +378,7 @@ def get_tick_iterators(self, axes): angle_normal, angle_tangent = 90, 0 else: angle_normal, angle_tangent = 0, 90 - + #angle = 90 - 90 * self.nth_coord major = self.axis.major @@ -459,7 +459,7 @@ def new_fixed_axis(self, loc, offset=None, axes=None, ): - + if axes is None: warnings.warn("'new_fixed_axis' explicitly requires the axes keyword.") axes = self.axes @@ -733,9 +733,9 @@ def draw(self, renderer, inframe=False): self.artists = orig_artists - def get_tightbbox(self, renderer): + def get_tightbbox(self, renderer, call_axes_locator=True): - bb0 = super(Axes, self).get_tightbbox(renderer) + bb0 = super(Axes, self).get_tightbbox(renderer, call_axes_locator) if not self._axisline_on: return bb0 @@ -777,13 +777,13 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, if not swap_axis: return - + if (x1o > x2o and x1 < x2) or (x1o < x2o and x1 > x2): - self.axis["right"], self.axis["left"] = self.axis["left"], self.axis["right"] + self.axis["right"], self.axis["left"] = self.axis["left"], self.axis["right"] self.axis["left"].set_axis_direction("left") self.axis["right"].set_axis_direction("right") - + def set_ylim(self, bottom=None, top=None, emit=True, auto=False, swap_axis=True, **kw): @@ -794,11 +794,11 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, y1, y2 = self.get_ylim() if y1o > y2o and y1 < y2 or (y1o < y2o and y1 > y2): - self.axis["top"], self.axis["bottom"] = self.axis["bottom"], self.axis["top"] + self.axis["top"], self.axis["bottom"] = self.axis["bottom"], self.axis["top"] self.axis["top"].set_axis_direction("top") self.axis["bottom"].set_axis_direction("bottom") - + Subplot = maxes.subplot_class_factory(Axes) From 83601268bb148ded489f9a65be7de85edd0d47e5 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Fri, 19 Aug 2011 11:36:06 -1000 Subject: [PATCH 089/214] collections: fix bug in scatter with log scale; handle masked offsets This was prompted by the following email: http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg21760.html --- lib/matplotlib/collections.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 2d08e37aeb86..ee9b19db9bb2 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -101,7 +101,7 @@ def __init__(self, # Force _offsets to be Nx2 self._offsets.shape = (0, 2) if offsets is not None: - offsets = np.asarray(offsets) + offsets = np.asanyarray(offsets) offsets.shape = (-1, 2) # Make it Nx2 if transOffset is not None: self._offsets = offsets @@ -160,7 +160,10 @@ def get_datalim(self, transData): offsets = transOffset.transform_non_affine(offsets) transOffset = transOffset.get_affine() - offsets = np.asarray(offsets, np.float_) + offsets = np.asanyarray(offsets, np.float_) + if np.ma.isMaskedArray(offsets): + offsets = offsets.filled(np.nan) + # get_path_collection_extents handles nan but not masked arrays offsets.shape = (-1, 2) # Make it Nx2 result = mpath.get_path_collection_extents( @@ -198,7 +201,7 @@ def _prepare_points(self): ys = self.convert_yunits(offsets[:,1]) offsets = zip(xs, ys) - offsets = np.asarray(offsets, np.float_) + offsets = np.asanyarray(offsets, np.float_) offsets.shape = (-1, 2) # Make it Nx2 if not transform.is_affine: @@ -206,8 +209,14 @@ def _prepare_points(self): transform = transform.get_affine() if not transOffset.is_affine : offsets = transOffset.transform_non_affine(offsets) + # This might have changed an ndarray into a masked array. transOffset = transOffset.get_affine() + if np.ma.isMaskedArray(offsets): + offsets = offsets.filled(np.nan) + # Changing from a masked array to nan-filled ndarray + # is probably most efficient at this point. + return transform, transOffset, offsets, paths @allow_rasterization @@ -289,7 +298,7 @@ def set_offsets(self, offsets): ACCEPTS: float or sequence of floats """ - offsets = np.asarray(offsets, np.float_) + offsets = np.asanyarray(offsets, np.float_) offsets.shape = (-1, 2) # Make it Nx2 #This decision is based on how they are initialized above if self._uniform_offsets is None: @@ -588,13 +597,13 @@ def __init__(self, paths, sizes=None, **kwargs): def set_paths(self, paths): self._paths = paths - + def get_paths(self): return self._paths - + def get_sizes(self): return self._sizes - + @allow_rasterization def draw(self, renderer): if self._sizes is not None: From 656ca9d38300a83ae5604eab1fb8bf856fbacc53 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Fri, 19 Aug 2011 12:00:59 -1000 Subject: [PATCH 090/214] locale formatting: minor docstring and comment cleanups --- lib/matplotlib/axes.py | 2 +- matplotlibrc.template | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index e7ce05908147..fd788b211247 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2109,7 +2109,7 @@ def ticklabel_format(self, **kwargs): used. *axis* [ 'x' | 'y' | 'both' ] *useLocale* If True, format the number according to - the current locale. The affects things + the current locale. This affects things such as the character used for the decimal separator. If False, use C-style (English) formatting. The diff --git a/matplotlibrc.template b/matplotlibrc.template index a1675fe46170..113774c0c6d8 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -212,10 +212,13 @@ backend : %(backend)s #axes.formatter.limits : -7, 7 # use scientific notation if log10 # of the axis range is smaller than the # first or larger than the second -#axes.formatter.use_locale : False # When True, format tick labels according to the user's locale. - # For example, use ',' as a decimal separator in the fr_FR locale. +#axes.formatter.use_locale : False # When True, format tick labels + # according to the user's locale. + # For example, use ',' as a decimal + # separator in the fr_FR locale. #axes.unicode_minus : True # use unicode for the minus symbol - # rather than hypen. See http://en.wikipedia.org/wiki/Plus_sign#Plus_sign + # rather than hypen. See + # http://en.wikipedia.org/wiki/Plus_sign #axes.color_cycle : b, g, r, c, m, y, k # color cycle for plot lines # as list of string colorspecs: # single letter, long name, or From 356c996a666a36eba82ce8ee4812458106a05599 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Fri, 19 Aug 2011 13:55:03 -1000 Subject: [PATCH 091/214] gc: ensure explicitly set alpha overrides the A in rgba. Prior to this change, calling set_alpha before set_foreground with an rgba argument would cause the latter to override the former. --- lib/matplotlib/backend_bases.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 226cc8132a10..45de70422c5a 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -637,6 +637,7 @@ class GraphicsContextBase: def __init__(self): self._alpha = 1.0 + self._forced_alpha = False # if True, _alpha overrides A from RGBA self._antialiased = 1 # use 0,1 not True, False for extension code self._capstyle = 'butt' self._cliprect = None @@ -772,6 +773,7 @@ def set_alpha(self, alpha): """ if alpha is not None: self._alpha = alpha + self._forced_alpha = True def set_antialiased(self, b): """ @@ -824,15 +826,14 @@ def set_foreground(self, fg, isRGB=False): html hex color string, an rgb or rgba unit tuple, or a float between 0 and 1. In the latter case, grayscale is used. - The :class:`GraphicsContextBase` converts colors to rgb - internally. If you know the color is rgb or rgba already, you can set - ``isRGB=True`` to avoid the performace hit of the conversion + If you know fg is rgb or rgba, set ``isRGB=True`` for + efficiency. """ if isRGB: self._rgb = fg else: self._rgb = colors.colorConverter.to_rgba(fg) - if len(self._rgb) == 4: + if len(self._rgb) == 4 and not self._forced_alpha: self._alpha = self._rgb[3] def set_graylevel(self, frac): From a96422e091d0222274af9027e7429ed0f8c00f06 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Fri, 19 Aug 2011 16:57:26 -1000 Subject: [PATCH 092/214] axis.py: clarify docstring for set_view_interval. Closes issue #118. Longer term, set_view interval could be deprecated and renamed, but this is very low priority. --- lib/matplotlib/axis.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 824fc87c3ef2..d5517b12dd28 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1724,7 +1724,11 @@ def set_view_interval(self, vmin, vmax, ignore=False): """ If *ignore* is *False*, the order of vmin, vmax does not matter; the original axis orientation will - be preserved. + be preserved. In addition, the view limits can be + expanded, but will not be reduced. This method is + for mpl internal use; for normal use, see + :meth:`~matplotlib.axes.Axes.set_xlim`. + """ if ignore: self.axes.viewLim.intervalx = vmin, vmax @@ -1986,7 +1990,11 @@ def set_view_interval(self, vmin, vmax, ignore=False): """ If *ignore* is *False*, the order of vmin, vmax does not matter; the original axis orientation will - be preserved. + be preserved. In addition, the view limits can be + expanded, but will not be reduced. This method is + for mpl internal use; for normal use, see + :meth:`~matplotlib.axes.Axes.set_ylim`. + """ if ignore: self.axes.viewLim.intervaly = vmin, vmax From dde91be00661044a53ff87e457e07be8a58ed8b8 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sat, 20 Aug 2011 19:12:10 -0500 Subject: [PATCH 093/214] Some additions to the API list. --- doc/api/animation_api.rst | 12 ++++++++++++ doc/api/index.rst | 7 +++++-- doc/api/legend_api.rst | 12 ++++++++++++ doc/api/tight_layout_api.rst | 12 ++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 doc/api/animation_api.rst create mode 100644 doc/api/legend_api.rst create mode 100644 doc/api/tight_layout_api.rst diff --git a/doc/api/animation_api.rst b/doc/api/animation_api.rst new file mode 100644 index 000000000000..d43dc351abae --- /dev/null +++ b/doc/api/animation_api.rst @@ -0,0 +1,12 @@ +********* +animation +********* + + +:mod:`matplotlib.animation` +=========================== + +.. automodule:: matplotlib.animation + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/index.rst b/doc/api/index.rst index 640cc82d410b..0252e72485fa 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -15,9 +15,11 @@ api_changes.rst matplotlib_configuration_api.rst afm_api.rst + animation_api.rst artist_api.rst axes_api.rst axis_api.rst + index_backend_api.rst cbook_api.rst cm_api.rst collections_api.rst @@ -27,13 +29,14 @@ figure_api.rst font_manager_api.rst gridspec_api.rst + legend_api.rst mathtext_api.rst mlab_api.rst + nxutils_api.rst path_api.rst pyplot_api.rst - nxutils_api.rst spines_api.rst ticker_api.rst + tight_layout_api.rst units_api.rst - index_backend_api.rst widgets_api.rst diff --git a/doc/api/legend_api.rst b/doc/api/legend_api.rst new file mode 100644 index 000000000000..7ad075d33cae --- /dev/null +++ b/doc/api/legend_api.rst @@ -0,0 +1,12 @@ +****** +legend +****** + + +:mod:`matplotlib.legend` +========================= + +.. automodule:: matplotlib.legend + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/tight_layout_api.rst b/doc/api/tight_layout_api.rst new file mode 100644 index 000000000000..11cdaa9b71da --- /dev/null +++ b/doc/api/tight_layout_api.rst @@ -0,0 +1,12 @@ +************ +tight_layout +************ + + +:mod:`matplotlib.tight_layout` +============================== + +.. automodule:: matplotlib.tight_layout + :members: + :undoc-members: + :show-inheritance: From 6c4e61d4633a8155f8ca41dea2515853d9ba3066 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sat, 20 Aug 2011 19:13:52 -0500 Subject: [PATCH 094/214] Further work in polishing the documentation for the upcoming release. --- doc/mpl_toolkits/mplot3d/api.rst | 4 ++++ doc/users/legend_guide.rst | 28 ++++++++++++----------- doc/users/whats_new.rst | 38 ++++++++++++++++++++------------ lib/matplotlib/legend.py | 6 ++--- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/doc/mpl_toolkits/mplot3d/api.rst b/doc/mpl_toolkits/mplot3d/api.rst index b274621439ee..64217a482fe2 100644 --- a/doc/mpl_toolkits/mplot3d/api.rst +++ b/doc/mpl_toolkits/mplot3d/api.rst @@ -19,6 +19,7 @@ mplot3d API .. automodule:: mpl_toolkits.mplot3d.axes3d :members: + :undoc-members: :show-inheritance: @@ -38,6 +39,7 @@ mplot3d API .. automodule:: mpl_toolkits.mplot3d.axis3d :members: + :undoc-members: :show-inheritance: .. _toolkit_mplot3d-artapi: @@ -47,6 +49,7 @@ mplot3d API .. automodule:: mpl_toolkits.mplot3d.art3d :members: + :undoc-members: :show-inheritance: .. _toolkit_mplot3d-projapi: @@ -56,5 +59,6 @@ mplot3d API .. automodule:: mpl_toolkits.mplot3d.proj3d :members: + :undoc-members: :show-inheritance: diff --git a/doc/users/legend_guide.rst b/doc/users/legend_guide.rst index 206fd4f14d06..0715fcd8040c 100644 --- a/doc/users/legend_guide.rst +++ b/doc/users/legend_guide.rst @@ -4,8 +4,8 @@ Legend guide ************ -Do not proceed unless you already have read :func:`~matplotlib.pyplot.legend` and -:class:`matplotlib.legend.Legend`! +Do not proceed unless you already have read :func:`~matplotlib.pyplot.legend` +and :class:`matplotlib.legend.Legend`! What to be displayed @@ -30,7 +30,7 @@ returns a tuple of two lists, i.e., list of artists and list of labels (python string). However, it does not return all of its child artists. It returns artists that are currently supported by matplotlib. -For matplotlib v1.0 and before, the supported artists are as follows. +For matplotlib v1.0 and earlier, the supported artists are as follows. * :class:`~matplotlib.lines.Line2D` * :class:`~matplotlib.patches.Patch` @@ -186,11 +186,12 @@ legend. .. plot:: users/plotting/examples/simple_legend02.py :include-source: +.. _legend-complex-plots: Legend of Complex Plots ======================= -In matplotlib v1.1 (FIXME when released) and later, the legend is +In matplotlib v1.1 and later, the legend is improved to support more plot commands and ease the customization. Artist Container @@ -224,7 +225,7 @@ or :: legend([b1], ["Bar 1"]) -At this time of writing, however, "bar" and "errorbar" are only +At this time of writing, however, only "bar", "errorbar", and "stem" are supported (hopefully the list will increase). Here is an example. .. plot:: mpl_examples/pylab_examples/legend_demo4.py @@ -232,7 +233,7 @@ supported (hopefully the list will increase). Here is an example. Legend Handler -------------- -One of the change is that drawing of legend handles is delegated to +One of the changes is that drawing of legend handles has been delegated to legend handlers. For example, :class:`~matplotlib.lines.Line2D` instances are handled by :class:`~matplotlib.legend_handler.HandlerLine2D`. The mapping @@ -247,8 +248,9 @@ Let's consider the following sample code, :: For each *p_i*, matplotlib - 1. check if *p_i* itself is in the handler_map - 2. if not, iterate over type(p_i).mro() until a matching key is found in the handler_map + 1. check if *p_i* is in the handler_map + 2. if not, iterate over type(p_i).mro() until a matching key is found + in the handler_map Unless specified, the defaul handler_map is used. Below is a partial @@ -260,7 +262,7 @@ list of key-handler pairs included in the default handler map. * ... -The legend command takes an optional argument of "handler_map". When +The legend() command takes an optional argument of "handler_map". When provided, the default handler map will be updated (using dict.update method) with the provided one. :: @@ -279,9 +281,9 @@ instances (p1 and p2). :: In the above example, only *p1* will be handled by *my_handler*, while others will be handled by default handlers. -The curent default handler_map has handlers for errobar and bar +The curent default handler_map has handlers for errorbar and bar plots. Also, it includes an entry for `tuple` which is mapped to -`HandlerTuple`. It simply overplots all the handles for items in the +`HandlerTuple`. It simply plots over all the handles for items in the given tuple. For example, @@ -312,5 +314,5 @@ pixles, and *handlebox* is a OffsetBox instance. Within the call, you create relevant artists (using relevant properties from the *legend* and/or *orig_handle*) and add them into the handlebox. The artists needs to be scaled according to the fontsize (note that the size is in -pixel, i.e., this is dpi-scaled value). See legend_handler.py for more -details. +pixel, i.e., this is dpi-scaled value). See :mod:`~matplotlib.legend_handler` +for more details. diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 58c1812d5428..44e3c6d09d88 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -19,24 +19,28 @@ Animation Ryan May invested significant effort to create a backend-independent framework for creating animated figures. The :mod:`~matplotlib.animation` module is intended to replace the difficult-to-understand, -backend-specific examples that has existed in the examples listing. +backend-specific examples that used to exist in the :ref:`examples-index` +listings. This framework should be considered a beta feature for matplotlib, but we highly encourage users to try it out and provide feedback. +Check out the :ref:`animation-examples-index` and try them out! + + Tight Layout ------------ A frequent issue raised by users of matplotlib is the lack of a layout -engine to nicely space out elements of the plots. While we still adhere -to the philosphy of giving users complete control over the placement of -plot elements, a :mod:`~matplotlib.tight_layout` module was created to -address the most common layout issues. +engine to nicely space out elements of the plots. While matplotlib still +adheres to the philosphy of giving users complete control over the placement +of plot elements, Jae-Joon Lee created the :mod:`~matplotlib.tight_layout` +module to address the most common layout issues. :mod:`~matplotlib.tight_layout` will adjust the spacing between subplots -so that the axis labels do not overlap with neighboring subplots. - -Need to acknowledge author +so that the axis labels do not overlap with neighboring subplots. A +:ref:`plotting-guide-tight-layout` has been created to show how to use +this new tool. Full IPython 0.11 compatibility ------------------------------- @@ -49,11 +53,16 @@ is fully compatible with ipython. Legend ------ -Jae-Joon Lee has been working on revamping how plot legends are handled +Jae-Joon Lee has also been working on revamping how plot legends are handled in matplotlib. This has resulted in some immediate enhancements. First, -legends for :func:`~matplotlib.pyplot.stem` plots will now display -correctly. Second, the 'best' placement of a legend has been improved -in the presence of NaNs. +legends for complex plots such as :func:`~matplotlib.pyplot.stem` plots +will now display correctly. Second, the 'best' placement of a legend has +been improved in the presence of NANs. + +See :ref:`legend-complex-plots` for more detailed explanation and +examples. + +.. plot:: mpl_examples/pylab_examples/legend_demo4.py mplot3d ------- @@ -66,14 +75,15 @@ as 2D plotting, Ben Root has made several improvements to the improved to bring the class towards feature-parity with regular Axes objects -* Documentation for the mplot3d module was significantly expanded. +* Documentation for :ref:`toolkit_mplot3d-index` was significantly expanded * Axis labels and orientation improved * Ticker offset display added * :func:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` - gains *zdir* and *offset* kwargs. + gains *zdir* and *offset* kwargs +.. plot:: mpl_examples/mplot3d/contourf3d_demo2.py * Most 3D plotting functions now support empty inputs diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 663b6a7d94ac..ae546bf55096 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -7,9 +7,9 @@ plot elements in the axes or figures (e.g., lines, patches, etc.) are specified by the handler map, which defines the mapping between the plot elements and the legend handlers to be used (the default legend -handlers are defined in the matplotlib.legend_handler module). Note -that not all kinds of artist are supported by the legend yet (See LINK -(FIXME) for details). +handlers are defined in the :mod:`~matplotlib.legend_handler` module). Note +that not all kinds of artist are supported by the legend yet (See +:ref:`plotting-guide-legend` for more information). """ from __future__ import division import warnings From 6128bd5342ec922c80b687f599247c41acd3b67f Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sat, 20 Aug 2011 21:54:09 -0500 Subject: [PATCH 095/214] Added a new mplot3d example to demonstrate the offset display --- doc/users/whats_new.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 44e3c6d09d88..16b4761454ec 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -79,14 +79,15 @@ as 2D plotting, Ben Root has made several improvements to the * Axis labels and orientation improved -* Ticker offset display added +* Most 3D plotting functions now support empty inputs + +* Ticker offset display added: +.. plot:: mpl_examples/mplot3d/offset_demo.py * :func:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` - gains *zdir* and *offset* kwargs + gains *zdir* and *offset* kwargs. You can now do this: .. plot:: mpl_examples/mplot3d/contourf3d_demo2.py -* Most 3D plotting functions now support empty inputs - Numerix support removed ----------------------- From 44e36cbaa565eca4e9111d766cd6f1a7f235f4f3 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sun, 21 Aug 2011 14:44:18 -0500 Subject: [PATCH 096/214] Started a new section in API changes, as well as updating information for imshow() --- doc/api/api_changes.rst | 31 +++++++++++++++++++++++++++++-- doc/users/whats_new.rst | 31 +++++++++++++++++-------------- lib/matplotlib/axes.py | 6 +++++- lib/matplotlib/image.py | 2 +- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index e7a95b23bdd4..4bcace995e7a 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -5,7 +5,34 @@ API Changes This chapter is a log of changes to matplotlib that affect the outward-facing API. If updating matplotlib breaks your scripts, this -list may help describe what changes may be necessary in your code. +list may help describe what changes may be necessary in your code or +help figure out possible sources of the changes you are experiencing. + +For new features that were added to matplotlib, please see +:ref:`whats-new`. + +Changes in 1.1.x +================ + +* In :meth:`~matplotlib.pyplot.imshow`, setting *interpolation* to 'nearest' + will now always mean that the nearest-neighbor interpolation is performed. + If you want the no-op interpolation to be performed, choose 'none'. + +* There were errors in how the tri-functions were handling input parameters + that had to be fixed. If your tri-plots are not working correctly anymore, + or you were working around apparent mistakes, please see issue #203 in the + github tracker. When in doubt, use kwargs. + +* The 'symlog' scale had some bad behavior in previous versions. This has now + been fixed and users should now be able to use it without frustrations. + The fixes did result in some minor changes in appearance for some users who + may have been depending on the bad behavior. + +* There is now a common set of markers for all plotting functions. Previously, + some markers existed only for :meth:`~matplotlib.pyplot.scatter` or just for + :meth:`~matplotlib.pyplot.plot`. This is now no longer the case. This merge + did result in a conflict. The string 'd' now means "thin diamond" while + 'D' will mean "regular diamond". Changes beyond 0.99.x ===================== @@ -50,7 +77,7 @@ Changes beyond 0.99.x * The :meth:`matplotlib.axes.Axes.hist` *color* kwarg now accepts a sequence of color specs to match a sequence of datasets. -* The :class:'~matplotlib.collections.EllipseCollection' has been +* The :class:`~matplotlib.collections.EllipseCollection` has been changed in two ways: + There is a new *units* option, 'xy', that scales the ellipse with diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 16b4761454ec..be38cc1bbc9c 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -55,7 +55,7 @@ Legend Jae-Joon Lee has also been working on revamping how plot legends are handled in matplotlib. This has resulted in some immediate enhancements. First, -legends for complex plots such as :func:`~matplotlib.pyplot.stem` plots +legends for complex plots such as :meth:`~matplotlib.pyplot.stem` plots will now display correctly. Second, the 'best' placement of a legend has been improved in the presence of NANs. @@ -84,7 +84,7 @@ as 2D plotting, Ben Root has made several improvements to the * Ticker offset display added: .. plot:: mpl_examples/mplot3d/offset_demo.py -* :func:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` +* :meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` gains *zdir* and *offset* kwargs. You can now do this: .. plot:: mpl_examples/mplot3d/contourf3d_demo2.py @@ -97,8 +97,8 @@ now been completely removed from matplotlib. Markers ------- -The list of available markers for :func:`~matplotlib.pyplot.plot` and -:func:`~matplotlib.pyplot.scatter` has now been merged. While they +The list of available markers for :meth:`~matplotlib.pyplot.plot` and +:meth:`~matplotlib.pyplot.scatter` has now been merged. While they were mostly similar, some markers existed for one function, but not the other. This merge did result in a conflict for the 'd' diamond marker. Now, 'd' will be interpreated to always mean "thin" diamond @@ -111,30 +111,33 @@ Other improvements * Unit support for polar axes and :func:`~matplotlib.axes.Axes.arrow` -* :class:`~matplotlib.projections.polar.PolarAxes` gains - 'set_theta_direction', 'set_theta_zero_direction' and - 'set_theta_offset' functions. +* :class:`~matplotlib.projections.polar.PolarAxes` gains getters and setters for + "theta_direction", and "theta_offset" to allow for theta to go in + either the clock-wise or counter-clockwise direction and to specify where zero + degrees should be placed. + :meth:`~matplotlib.projections.polar.PolarAxes.set_theta_zero_location` is an + added convenience function. * Fixed error in argument handling for tri-functions such as - :func:`~matplotlib.pyplot.tripcolor` + :meth:`~matplotlib.pyplot.tripcolor` -* 'axes.labelweight' parameter added to rcParams. +* ``axes.labelweight`` parameter added to rcParams. -* For :func:`~matplotlib.pyplot.imshow`, *interpolation='nearest'* will - now always perform an interpolation. A 'none' option has been added to +* For :meth:`~matplotlib.pyplot.imshow`, *interpolation='nearest'* will + now always perform an interpolation. A "none" option has been added to indicate no interpolation at all. * An error in the Hammer projection has been fixed. -* *clabel* for :func:`~matplotlib.pyplot.contour` now accepts a callable. +* *clabel* for :meth:`~matplotlib.pyplot.contour` now accepts a callable. Thanks to Daniel Hyams for the original patch! * Jae-Joon Lee added the :class:`~mpl_toolkits.axes_grid1.axes_divider.HBox` and :class:`~mpl_toolkits.axes_grid1.axes_divider.VBox` classes. -* Christoph Gohike improved memory usage in :func:`~matplotlib.pyplot.imshow`. +* Christoph Gohike improved memory usage in :meth:`~matplotlib.pyplot.imshow`. -* :func:`~matplotlib.pyplot.scatter` now accepts empty inputs. +* :meth:`~matplotlib.pyplot.scatter` now accepts empty inputs. * The behavior for 'symlog' scale has been fixed, but this may result in some minor changes to existing plots. diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index b82e6e777184..756f6d5cf86c 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -6645,7 +6645,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, *interpolation*: - Acceptable values are *None*, 'nearest', 'bilinear', + Acceptable values are *None*, 'none', 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos' @@ -6654,6 +6654,10 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, ``image.interpolation``. See also the *filternorm* and *filterrad* parameters + If *interpolation* is 'none', then no interpolation is performed + on the Agg, ps and pdf backends. Other backends will fall back to + 'nearest'. + *norm*: [ None | Normalize ] An :class:`matplotlib.colors.Normalize` instance; if *None*, default is ``normalization()``. This scales diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index e46b949425bb..12711ec55370 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -439,7 +439,7 @@ def get_interpolation(self): One of 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', - 'bessel', 'mitchell', 'sinc', 'lanczos', + 'bessel', 'mitchell', 'sinc', 'lanczos', or 'none'. """ return self._interpolation From fca4bafda37d4c3358716c5617632c52e575170c Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 21 Aug 2011 10:04:13 -1000 Subject: [PATCH 097/214] embedding_in_tk examples: improve the first, delete the second --- examples/user_interfaces/embedding_in_tk.py | 17 +++++--- examples/user_interfaces/embedding_in_tk2.py | 42 -------------------- 2 files changed, 12 insertions(+), 47 deletions(-) delete mode 100644 examples/user_interfaces/embedding_in_tk2.py diff --git a/examples/user_interfaces/embedding_in_tk.py b/examples/user_interfaces/embedding_in_tk.py index f508303fa6d8..e021f308aded 100644 --- a/examples/user_interfaces/embedding_in_tk.py +++ b/examples/user_interfaces/embedding_in_tk.py @@ -1,4 +1,5 @@ #!/usr/bin/env python + import matplotlib matplotlib.use('TkAgg') @@ -9,11 +10,8 @@ import Tkinter as Tk import sys -def destroy(e): sys.exit() - root = Tk.Tk() root.wm_title("Embedding in TK") -#root.bind("", destroy) f = Figure(figsize=(5,4), dpi=100) @@ -33,7 +31,16 @@ def destroy(e): sys.exit() toolbar.update() canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) -#button = Tk.Button(master=root, text='Quit', command=sys.exit) -#button.pack(side=Tk.BOTTOM) +def _quit(): + root.quit() # stops mainloop + root.destroy() # this is necessary on Windows to prevent + # Fatal Python Error: PyEval_RestoreThread: NULL tstate + +button = Tk.Button(master=root, text='Quit', command=_quit) +button.pack(side=Tk.BOTTOM) Tk.mainloop() +# If you put root.destroy() here, it will cause an error if +# the window is closed with the window manager. + + diff --git a/examples/user_interfaces/embedding_in_tk2.py b/examples/user_interfaces/embedding_in_tk2.py deleted file mode 100644 index 37366cedb554..000000000000 --- a/examples/user_interfaces/embedding_in_tk2.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -import matplotlib -matplotlib.use('TkAgg') - -from numpy import arange, sin, pi -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg -from matplotlib.figure import Figure - -import Tkinter as Tk -import sys - -def destroy(e): sys.exit() - -root = Tk.Tk() -root.wm_title("Embedding in TK") -#root.bind("", destroy) - - -f = Figure(figsize=(5,4), dpi=100) -a = f.add_subplot(111) -t = arange(0.0,3.0,0.01) -s = sin(2*pi*t) - -a.plot(t,s) -a.set_title('Tk embedding') -a.set_xlabel('X axis label') -a.set_ylabel('Y label') - - -# a tk.DrawingArea -canvas = FigureCanvasTkAgg(f, master=root) -canvas.show() -canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) - -#toolbar = NavigationToolbar2TkAgg( canvas, root ) -#toolbar.update() -canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) - -button = Tk.Button(master=root, text='Quit', command=sys.exit) -button.pack(side=Tk.BOTTOM) - -Tk.mainloop() From fb114682d3573edb099b4374c699431cc206f39c Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Tue, 23 Aug 2011 11:41:41 +0900 Subject: [PATCH 098/214] implement offsetbox.PaddedBox --- lib/matplotlib/offsetbox.py | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 8e4926ff1957..c019e17c8e04 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -406,6 +406,89 @@ def get_extent_offsets(self, renderer): + +class PaddedBox(OffsetBox): + def __init__(self, child, pad=None, draw_frame=False, patch_attrs=None): + """ + *pad* : boundary pad + + .. note:: + *pad* need to given in points and will be + scale with the renderer dpi, while *width* and *hight* + need to be in pixels. + """ + + super(PaddedBox, self).__init__() + + self.pad = pad + self._children = [child] + + self.patch = FancyBboxPatch( + xy=(0.0, 0.0), width=1., height=1., + facecolor='w', edgecolor='k', + mutation_scale=1, #self.prop.get_size_in_points(), + snap=True + ) + + self.patch.set_boxstyle("square",pad=0) + + if patch_attrs is not None: + self.patch.update(patch_attrs) + + self._drawFrame = draw_frame + + + def get_extent_offsets(self, renderer): + """ + update offset of childrens and return the extents of the box + """ + + dpicor = renderer.points_to_pixels(1.) + pad = self.pad * dpicor + + w, h, xd, yd = self._children[0].get_extent(renderer) + + return w + 2*pad, h + 2*pad, \ + xd+pad, yd+pad, \ + [(0, 0)] + + + def draw(self, renderer): + """ + Update the location of children if necessary and draw them + to the given *renderer*. + """ + + width, height, xdescent, ydescent, offsets = self.get_extent_offsets(renderer) + + px, py = self.get_offset(width, height, xdescent, ydescent, renderer) + + for c, (ox, oy) in zip(self.get_visible_children(), offsets): + c.set_offset((px+ox, py+oy)) + + self.draw_frame(renderer) + + for c in self.get_visible_children(): + c.draw(renderer) + + #bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + + def update_frame(self, bbox, fontsize=None): + self.patch.set_bounds(bbox.x0, bbox.y0, + bbox.width, bbox.height) + + if fontsize: + self.patch.set_mutation_scale(fontsize) + + def draw_frame(self, renderer): + # update the location and size of the legend + bbox = self.get_window_extent(renderer) + self.update_frame(bbox) + + if self._drawFrame: + self.patch.draw(renderer) + + class DrawingArea(OffsetBox): """ The DrawingArea can contain any Artist as a child. The DrawingArea From eff1069a3e6a416deaea700d42fe46852fce7322 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Tue, 23 Aug 2011 11:51:28 +0900 Subject: [PATCH 099/214] fixes a bug that signs are sometime wrong when FormatterDMS is used --- lib/mpl_toolkits/axisartist/angle_helper.py | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/mpl_toolkits/axisartist/angle_helper.py b/lib/mpl_toolkits/axisartist/angle_helper.py index 0d72a78542af..0da37420f1fd 100644 --- a/lib/mpl_toolkits/axisartist/angle_helper.py +++ b/lib/mpl_toolkits/axisartist/angle_helper.py @@ -142,7 +142,7 @@ def select_step(v1, v2, nv, hour=False, include_last=True): levs = levs[0] + np.arange(0, nv+1, 1) * step else: levs = levs[0] + np.arange(0, nv, 1) * step - + n = len(levs) return np.array(levs), n, factor @@ -229,25 +229,31 @@ def __call__(self, direction, factor, values): #ss = [[-1, 1][v>0] for v in values] #not py24 compliant values = np.asarray(values) ss = np.where(values>0, 1, -1) + + sign_map = {(-1, True):"-"} + signs = [sign_map.get((s, v!=0), "") for s, v in zip(ss, values)] + values = np.abs(values) + if factor == 1: return ["$%d^{\circ}$" % (s*int(v),) for (s, v) in zip(ss, values)] elif factor == 60: - return ["$%d^{\circ}\,%02d^{\prime}$" % (s*floor(v/60.), v%60) \ - for s, v in zip(ss, values)] + return ["$%s%d^{\circ}\,%02d^{\prime}$" % (s,floor(v/60.), v%60) \ + for s, v in zip(signs, values)] elif factor == 3600: if ss[-1] == -1: inverse_order = True values = values[::-1] + sings = signs[::-1] else: inverse_order = False degree = floor(values[0]/3600.) - hm_fmt = "$%d^{\circ}\,%02d^{\prime}\," + hm_fmt = "$%s%d^{\circ}\,%02d^{\prime}\," s_fmt = "%02d^{\prime\prime}$" l_hm_old = "" r = [] - for v in values-3600*degree: - l_hm = hm_fmt % (ss[0]*degree, floor(v/60.)) + for v, s in zip(values-3600*degree, signs): + l_hm = hm_fmt % (s, degree, floor(v/60.)) l_s = s_fmt % (v%60,) if l_hm != l_hm_old: l_hm_old = l_hm @@ -353,3 +359,7 @@ def _adjust_extremes(self, lon_min, lon_max, lat_min, lat_max): print select_step(-180, 180, 10, hour=False) print select_step(-12, 12, 10, hour=True) + + fmt = FormatterDMS() + #print fmt("left", 60, [0, -30, -60]) + print fmt("left", 3600, [0, -30, -60]) From 0d4a2e16a6543523590652762f56bcdfce78090a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 23 Aug 2011 11:20:20 -0400 Subject: [PATCH 100/214] Put all clippaths in their own def at the end of the file so that they are accessible even when their referents are made invisible. Problem pointed out by David Huard on the mailing list in thread "Adding interactivity to an histogram in SVG". --- lib/matplotlib/backends/backend_svg.py | 61 +++++++++++++++++--------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 53e7346e2d70..661a7bcb221f 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -279,6 +279,8 @@ def __init__(self, width, height, svgwriter, basename=None): self._write_default_style() def finalize(self): + self._write_clips() + self._write_hatches() self._write_svgfonts() self.writer.close(self._start_id) @@ -321,26 +323,35 @@ def _get_hatch(self, gc, rgbFace): """ Create a new hatch pattern """ - writer = self.writer - HATCH_SIZE = 72 dictkey = (gc.get_hatch(), rgbFace, gc.get_rgb()) oid = self._hatchd.get(dictkey) if oid is None: oid = self._make_id('h', dictkey) - writer.start('defs') + self._hatchd[dictkey] = ((gc.get_hatch_path(), rgbFace, gc.get_rgb()), oid) + else: + _, oid = oid + return oid + + def _write_hatches(self): + if not len(self._hatchd): + return + HATCH_SIZE = 72 + writer = self.writer + writer.start('defs') + for ((path, face, stroke), oid) in self._hatchd.values(): writer.start( 'pattern', id=oid, patternUnits="userSpaceOnUse", x="0", y="0", width=str(HATCH_SIZE), height=str(HATCH_SIZE)) path_data = self._convert_path( - gc.get_hatch_path(), + path, Affine2D().scale(HATCH_SIZE).scale(1.0, -1.0).translate(0, HATCH_SIZE), simplify=False) - if rgbFace is None: + if face is None: fill = 'none' else: - fill = rgb2hex(rgbFace) + fill = rgb2hex(face) writer.element( 'rect', x="0", y="0", width=str(HATCH_SIZE+1), height=str(HATCH_SIZE+1), @@ -349,17 +360,15 @@ def _get_hatch(self, gc, rgbFace): 'path', d=path_data, style=generate_css({ - 'fill': rgb2hex(gc.get_rgb()), - 'stroke': rgb2hex(gc.get_rgb()), + 'fill': rgb2hex(stroke), + 'stroke': rgb2hex(stroke), 'stroke-width': str(1.0), 'stroke-linecap': 'butt', 'stroke-linejoin': 'miter' }) ) writer.end('pattern') - writer.end('defs') - self._hatchd[dictkey] = oid - return oid + writer.end('defs') def _get_style(self, gc, rgbFace): """ @@ -409,22 +418,34 @@ def _get_clip(self, gc): else: return None - oid = self._clipd.get(dictkey) - if oid is None: - writer = self.writer + clip = self._clipd.get(dictkey) + if clip is None: oid = self._make_id('p', dictkey) - writer.start('defs') - writer.start('clipPath', id=oid) if clippath is not None: + self._clipd[dictkey] = ((clippath, clippath_trans), oid) + else: + self._clipd[dictkey] = (dictkey, oid) + else: + clip, oid = clip + return oid + + def _write_clips(self): + if not len(self._clipd): + return + writer = self.writer + writer.start('defs') + for clip, oid in self._clipd.values(): + writer.start('clipPath', id=oid) + if len(clip) == 2: + clippath, clippath_trans = clip path_data = self._convert_path(clippath, clippath_trans, simplify=False) writer.element('path', d=path_data) else: + x, y, w, h = clip writer.element('rect', x=str(x), y=str(y), width=str(w), height=str(h)) writer.end('clipPath') - writer.end('defs') - self._clipd[dictkey] = oid - return oid - + writer.end('defs') + def _write_svgfonts(self): if not rcParams['svg.fonttype'] == 'svgfont': return From 90f7d507ebadd2700e93974806b894a3fa7bf2e1 Mon Sep 17 00:00:00 2001 From: David Huard Date: Tue, 23 Aug 2011 14:33:59 -0400 Subject: [PATCH 101/214] add interactive svg histogram example. --- examples/user_interfaces/svg_histogram.py | 131 ++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 examples/user_interfaces/svg_histogram.py diff --git a/examples/user_interfaces/svg_histogram.py b/examples/user_interfaces/svg_histogram.py new file mode 100644 index 000000000000..e3d8067e3713 --- /dev/null +++ b/examples/user_interfaces/svg_histogram.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +#-*-encoding:utf8-*- + +""" +Demonstrate how to create an interactive histogram, in which bars +are hidden or shown by cliking on legend markers. + +The interactivity is encoded in ecmascript and inserted in the SVG code +in a post-processing step. To render the image, open it in a web +browser. SVG is supported in most web browsers used by Linux and OSX +users. Windows IE9 supports SVG, but earlier versions do not. + +__author__="david.huard@gmail.com" + +""" + +import numpy as np +import matplotlib.pyplot as plt +import xml.etree.ElementTree as ET +from StringIO import StringIO + +plt.rcParams['svg.embed_char_paths'] = 'none' + +# Apparently, this `register_namespace` method works only with +# python 2.7 and up and is necessary to avoid garbling the XML name +# space with ns0. +ET.register_namespace("","http://www.w3.org/2000/svg") + + +def python2js(d): + """Return a string representation of a python dictionary in + ecmascript object syntax.""" + + objs = [] + for key, value in d.items(): + objs.append( key + ':' + str(value) ) + + return '{' + ', '.join(objs) + '}' + + +# --- Create histogram, legend and title --- +plt.figure() +r = np.random.randn(100) +r1 = r + 1 +labels = ['Rabbits', 'Frogs'] +H = plt.hist([r,r1], label=labels) +containers = H[-1] +leg = plt.legend(frameon=False) +plt.title("""From a web browser, click on the legend +marker to toggle the corresponding histogram.""") + + +# --- Add ids to the svg objects we'll modify + +hist_patches = {} +for ic, c in enumerate(containers): + hist_patches['hist_%d'%ic] = [] + for il, element in enumerate(c): + element.set_gid('hist_%d_patch_%d'%(ic, il)) + hist_patches['hist_%d'%ic].append('hist_%d_patch_%d'%(ic,il)) + +# Set ids for the legend patches +for i, t in enumerate(leg.get_patches()): + t.set_gid('leg_patch_%d'%i) + +# Save SVG in a fake file object. +f = StringIO() +plt.savefig(f, format="svg") + +# Create XML tree from the SVG file. +tree, xmlid = ET.XMLID(f.getvalue()) + + +# --- Add interactivity --- + +# Add attributes to the patch objects. +for i, t in enumerate(leg.get_patches()): + el = xmlid['leg_patch_%d'%i] + el.set('cursor', 'pointer') + el.set('opacity', '1.0') + el.set('onclick', "toggle_element(evt, 'hist_%d')"%i) + +# Create script defining the function `toggle_element`. +# We create a global variable `container` that stores the patches id +# belonging to each histogram. Then a function "toggle_element" sets the +# visibility attribute of all patches of each histogram and the opacity +# of the marker itself. + +script = """ + +"""%python2js(hist_patches) + +# Insert the script and save to file. +tree.insert(0, ET.XML(script)) + +ET.ElementTree(tree).write("svg_histogram.svg") + + + From 62d3de5c4bceb92cb05273a3fe6ebfc8a045f736 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 23 Aug 2011 16:27:41 -0400 Subject: [PATCH 102/214] Fix encoding line --- examples/user_interfaces/svg_histogram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 examples/user_interfaces/svg_histogram.py diff --git a/examples/user_interfaces/svg_histogram.py b/examples/user_interfaces/svg_histogram.py old mode 100644 new mode 100755 index e3d8067e3713..8763bbec2f17 --- a/examples/user_interfaces/svg_histogram.py +++ b/examples/user_interfaces/svg_histogram.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -#-*-encoding:utf8-*- +#-*- encoding:utf-8 -*- """ Demonstrate how to create an interactive histogram, in which bars From edba4fc6d6413497e085b62aae4189789d323f0f Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 25 Aug 2011 09:46:44 -0400 Subject: [PATCH 103/214] Fixes to compile with Clang 2.8 (tested on Ubuntu 11.04) --- src/_path.cpp | 8 ++++---- src/cntr.c | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/_path.cpp b/src/_path.cpp index 12870b3c4bd5..82557dda88c6 100644 --- a/src/_path.cpp +++ b/src/_path.cpp @@ -1578,19 +1578,19 @@ _path_module::convert_to_svg(const Py::Tuple& args) #if PY_VERSION_HEX >= 0x02070000 char* str; str = PyOS_double_to_string(x, 'g', precision, 0, NULL); - p += snprintf(p, buffersize - (p - buffer), str); + p += snprintf(p, buffersize - (p - buffer), "%s", str); PyMem_Free(str); *p++ = ' '; str = PyOS_double_to_string(y, 'g', precision, 0, NULL); - p += snprintf(p, buffersize - (p - buffer), str); + p += snprintf(p, buffersize - (p - buffer), "%s", str); PyMem_Free(str); #else char str[64]; PyOS_ascii_formatd(str, 64, format, x); - p += snprintf(p, buffersize - (p - buffer), str); + p += snprintf(p, buffersize - (p - buffer), "%s", str); *p++ = ' '; PyOS_ascii_formatd(str, 64, format, y); - p += snprintf(p, buffersize - (p - buffer), str); + p += snprintf(p, buffersize - (p - buffer), "%s", str); #endif --wait; diff --git a/src/cntr.c b/src/cntr.c index 631471f89542..2a00bdf4458a 100644 --- a/src/cntr.c +++ b/src/cntr.c @@ -1366,8 +1366,8 @@ int reorder(double *xpp, double *ypp, short *kpp, int maxnsegs = npts/2 + 1; /* allocate maximum possible size--gross overkill */ - i0 = malloc(maxnsegs * sizeof(int)); - i1 = malloc(maxnsegs * sizeof(int)); + i0 = (int *)malloc(maxnsegs * sizeof(int)); + i1 = (int *)malloc(maxnsegs * sizeof(int)); /* Find the segments. */ iseg = 0; @@ -1400,7 +1400,7 @@ int reorder(double *xpp, double *ypp, short *kpp, /* Find the subpaths as sets of connected segments. */ - subp = malloc(nsegs * sizeof(int)); + subp = (int *)malloc(nsegs * sizeof(int)); for (i=0; i Date: Thu, 25 Aug 2011 13:31:59 -0400 Subject: [PATCH 104/214] Fix error reporting in png extension. --- src/_png.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/_png.cpp b/src/_png.cpp index a2342dc8ebd3..151c8da78b9d 100644 --- a/src/_png.cpp +++ b/src/_png.cpp @@ -234,7 +234,11 @@ Py::Object _png_module::write_png(const Py::Tuple& args) fclose(fp); } - return Py::Object(); + if (PyErr_Occurred()) { + throw Py::Exception(); + } else { + return Py::Object(); + } } static void _read_png_data(PyObject* py_file_obj, png_bytep data, png_size_t length) @@ -475,7 +479,13 @@ _png_module::read_png(const Py::Tuple& args) delete [] row_pointers[row]; } delete [] row_pointers; - return Py::asObject((PyObject*)A); + + if (PyErr_Occurred()) { + Py_DECREF((PyObject *)A); + throw Py::Exception(); + } else { + return Py::asObject((PyObject*)A); + } } extern "C" From a8c4233953433c085d1fdae60f7154828304c620 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Fri, 26 Aug 2011 15:59:59 -1000 Subject: [PATCH 105/214] backends: fix alpha handling for cairo and macosx There are two parts to this change. First, the cairo and macosx backends recycle the graphics context instead of making a new one with the new_gc() method, so the _alpha attribute must be reset to 1 at that point. Second, the GraphicsContextBase.set_foreground() method needs to call the set_alpha method instead of setting the _alpha attribute, so that the subclass method is called. --- lib/matplotlib/backend_bases.py | 7 ++++++- lib/matplotlib/backends/backend_cairo.py | 2 ++ lib/matplotlib/backends/backend_macosx.py | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 45de70422c5a..19419264043a 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -774,6 +774,8 @@ def set_alpha(self, alpha): if alpha is not None: self._alpha = alpha self._forced_alpha = True + else: + self._forced_alpha = False def set_antialiased(self, b): """ @@ -834,7 +836,10 @@ def set_foreground(self, fg, isRGB=False): else: self._rgb = colors.colorConverter.to_rgba(fg) if len(self._rgb) == 4 and not self._forced_alpha: - self._alpha = self._rgb[3] + self.set_alpha(self._rgb[3]) + # Use set_alpha method here so that subclasses will + # be calling their own version, which may set their + # own attributes. def set_graylevel(self, frac): """ diff --git a/lib/matplotlib/backends/backend_cairo.py b/lib/matplotlib/backends/backend_cairo.py index 2b33bb23011d..cb7b2f940e9f 100644 --- a/lib/matplotlib/backends/backend_cairo.py +++ b/lib/matplotlib/backends/backend_cairo.py @@ -283,6 +283,8 @@ def get_text_width_height_descent(self, s, prop, ismath): def new_gc(self): if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name()) self.gc.ctx.save() + self.gc._alpha = 1.0 + self.gc._forced_alpha = False # if True, _alpha overrides A from RGBA return self.gc diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index b39676a7c74f..3a6b6ffcbaf0 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -101,6 +101,8 @@ def draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, def new_gc(self): self.gc.save() self.gc.set_hatch(None) + self.gc._alpha = 1.0 + self.gc._forced_alpha = False # if True, _alpha overrides A from RGBA return self.gc def draw_gouraud_triangle(self, gc, points, colors, transform): From 3f82c550a36b3b14275a0183e1ee7870a37798a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Sepp=C3=A4nen?= Date: Sat, 27 Aug 2011 22:13:04 +0300 Subject: [PATCH 106/214] Fix multiple-encodings issue in dviread.PsfontsMap Also adds a test for that function. --- lib/matplotlib/dviread.py | 32 ++++++------ .../tests/baseline_images/dviread/test.map | 10 ++++ lib/matplotlib/tests/test_dviread.py | 50 +++++++++++++++++++ 3 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/dviread/test.map create mode 100644 lib/matplotlib/tests/test_dviread.py diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index 7aca0ed26b59..85fa70fe2148 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -713,31 +713,33 @@ def _register(self, words): There is some difference between 1: - # TODO this is a stopgap workaround, need to handle this correctly - matplotlib.verbose.report('Multiple encodings for %s = %s, skipping' - % (texname, psname), 'debug') - return - elif len(encodings) == 1: - encoding, = encodings - else: - encoding = None - eff = effects.split() effects = {} try: diff --git a/lib/matplotlib/tests/baseline_images/dviread/test.map b/lib/matplotlib/tests/baseline_images/dviread/test.map new file mode 100644 index 000000000000..eb5bea7a2076 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/dviread/test.map @@ -0,0 +1,10 @@ +% used by test_dviread.py +TeXfont1 PSfont1 Date: Sun, 28 Aug 2011 15:16:42 +0900 Subject: [PATCH 107/214] Modifying the MacOSX backend to make its interactive behavior consistent with the other backends --- lib/matplotlib/backends/backend_macosx.py | 15 ++++++----- src/_macosx.m | 32 ++++++++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index 3a6b6ffcbaf0..7addfefcd6fb 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -224,10 +224,12 @@ def draw_if_interactive(): it will be redrawn as soon as the event loop resumes via PyOS_InputHook. This function should be called after each draw event, even if matplotlib is not running interactively. - """ - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.invalidate() + """ + if matplotlib.is_interactive(): + figManager = Gcf.get_active() + if figManager is not None: + figManager.canvas.invalidate() + def new_figure_manager(num, *args, **kwargs): """ @@ -371,9 +373,8 @@ def notify_axes_change(fig): # This is ugly, but this is what tkagg and gtk are doing. # It is needed to get ginput() working. self.canvas.figure.show = lambda *args: self.show() - - def show(self): - self.canvas.draw() + if matplotlib.is_interactive(): + self.show() def close(self): Gcf.destroy(self.num) diff --git a/src/_macosx.m b/src/_macosx.m index ad78787df340..510e6e5a0528 100644 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -803,6 +803,7 @@ static int _get_snap(GraphicsContext* self, enum e_snap_mode* mode) self->color[0] = r; self->color[1] = g; self->color[2] = b; + self->color[3] = 1.0; Py_INCREF(Py_None); return Py_None; @@ -2279,7 +2280,7 @@ static CGRect _find_enclosing_rect(CGPoint points[3]) {"Arial", 14}, {"Helvetica", 15}, {"Avant Garde", 16}, - {"sans-serif", 10}, + {"sans-serif", 15}, {"Apple Chancery", 17}, {"Textile", 18}, {"Zapf Chancery", 19}, @@ -2364,8 +2365,8 @@ static CGRect _find_enclosing_rect(CGPoint points[3]) "Arial-BoldItalicMT"}, {"Helvetica", /* 15 */ "Helvetica-Bold", - "", - ""}, + "Arial-ItalicMT", + "Arial-BoldItalicMT"}, {"AvantGardeITC-Book", /* 16 */ "AvantGardeITC-Demi", "AvantGardeITC-BookOblique", @@ -2681,7 +2682,6 @@ static CGRect _find_enclosing_rect(CGPoint points[3]) PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL"); return NULL; } - if(!PyArg_ParseTuple(args, "ffu#Ofssf", &x, &y, @@ -3755,7 +3755,6 @@ static void _data_provider_release(void* info, const void* data, size_t size) [window setDelegate: view]; [window makeFirstResponder: view]; [[window contentView] addSubview: view]; - [window makeKeyAndOrderFront: nil]; nwin++; @@ -3788,6 +3787,20 @@ static void _data_provider_release(void* info, const void* data, size_t size) Py_TYPE(self)->tp_free((PyObject*)self); } +static PyObject* +FigureManager_show(FigureManager* self) +{ + Window* window = self->window; + if(window) + { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [window makeKeyAndOrderFront: nil]; + [pool release]; + } + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* FigureManager_destroy(FigureManager* self) { @@ -3804,6 +3817,11 @@ static void _data_provider_release(void* info, const void* data, size_t size) } static PyMethodDef FigureManager_methods[] = { + {"show", + (PyCFunction)FigureManager_show, + METH_NOARGS, + "Shows the window associated with the figure manager." + }, {"destroy", (PyCFunction)FigureManager_destroy, METH_NOARGS, @@ -4662,7 +4680,9 @@ -(void)save_figure:(id)sender NSText* messagebox = [[NSText alloc] initWithFrame: rect]; [messagebox setFont: font]; [messagebox setDrawsBackground: NO]; - [messagebox setEditable: NO]; + [messagebox setSelectable: NO]; + /* if selectable, the messagebox can become first responder, + * which is not supposed to happen */ rect = [messagebox frame]; rect.origin.y = 0.5 * (height - rect.size.height); [messagebox setFrameOrigin: rect.origin]; From 7d79a3b735ed8cc0655240d8a4ccc942e787dd1a Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 29 Aug 2011 12:50:36 +0900 Subject: [PATCH 108/214] make stix_fonts_demo.py to work with system of sys.maxunicode <= 0xffff --- examples/pylab_examples/stix_fonts_demo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/pylab_examples/stix_fonts_demo.py b/examples/pylab_examples/stix_fonts_demo.py index 356cd6527773..216355c80167 100755 --- a/examples/pylab_examples/stix_fonts_demo.py +++ b/examples/pylab_examples/stix_fonts_demo.py @@ -16,8 +16,9 @@ r'$\mathscr{Script}$'] if sys.maxunicode > 0xffff: + s = r'Direct Unicode: $\u23ce \mathrm{\ue0f2 \U0001D538}$' stests.append( - ur'Direct Unicode: $\u23ce \mathrm{\ue0f2 \U0001D538}$' + unicode(s, encoding="unicode_escape") ) from pylab import * From 9563c1788787b951f50f7ffdea7bd4a0c2d1bfbb Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 29 Aug 2011 13:46:35 +0900 Subject: [PATCH 109/214] modify make.py to include the copytree and ignore_patterns. This is for compatibility with python versions proir to 2.6 --- doc/make.py | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/doc/make.py b/doc/make.py index 2d368dd65eec..59e89e0906f7 100755 --- a/doc/make.py +++ b/doc/make.py @@ -5,6 +5,94 @@ import shutil import sys +# ignore_patterns and copytree funtions are copies of what is included +# in shutil.copytree of python v2.6 and later. + +try: + WindowsError +except NameError: + WindowsError = None + +def ignore_patterns(*patterns): + """Function that can be used as copytree() ignore parameter. + + Patterns is a sequence of glob-style patterns + that are used to exclude files""" + import fnmatch + def _ignore_patterns(path, names): + ignored_names = [] + for pattern in patterns: + ignored_names.extend(fnmatch.filter(names, pattern)) + return set(ignored_names) + return _ignore_patterns + +def copytree(src, dst, symlinks=False, ignore=None): + """Recursively copy a directory tree using copy2(). + + The destination directory must not already exist. + If exception(s) occur, an Error is raised with a list of reasons. + + If the optional symlinks flag is true, symbolic links in the + source tree result in symbolic links in the destination tree; if + it is false, the contents of the files pointed to by symbolic + links are copied. + + The optional ignore argument is a callable. If given, it + is called with the `src` parameter, which is the directory + being visited by copytree(), and `names` which is the list of + `src` contents, as returned by os.listdir(): + + callable(src, names) -> ignored_names + + Since copytree() is called recursively, the callable will be + called once for each directory that is copied. It returns a + list of names relative to the `src` directory that should + not be copied. + + XXX Consider this example code rather than the ultimate tool. + + """ + from shutil import copy2, Error, copystat + names = os.listdir(src) + if ignore is not None: + ignored_names = ignore(src, names) + else: + ignored_names = set() + + os.makedirs(dst) + errors = [] + for name in names: + if name in ignored_names: + continue + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if symlinks and os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + copytree(srcname, dstname, symlinks, ignore) + else: + # Will raise a SpecialFileError for unsupported file types + copy2(srcname, dstname) + # catch the Error from the recursive copytree so that we can + # continue with other files + except Error, err: + errors.extend(err.args[0]) + except EnvironmentError, why: + errors.append((srcname, dstname, str(why))) + try: + copystat(src, dst) + except OSError, why: + if WindowsError is not None and isinstance(why, WindowsError): + # Copying file access times may fail on Windows + pass + else: + errors.extend((src, dst, str(why))) + if errors: + raise Error, errors + + def copy_if_out_of_date(original, derived): if (not os.path.exists(derived) or os.stat(derived).st_mtime < os.stat(original).st_mtime): @@ -44,9 +132,9 @@ def html(): figures_dest_path = 'build/html/pyplots' if os.path.exists(figures_dest_path): shutil.rmtree(figures_dest_path) - shutil.copytree( + copytree( 'pyplots', figures_dest_path, - ignore=shutil.ignore_patterns("*.pyc")) + ignore=ignore_patterns("*.pyc")) # Clean out PDF files from the _images directory for filename in glob.glob('build/html/_images/*.pdf'): From f3b3242b04a072b21dfcc673abce24af6c228223 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Mon, 29 Aug 2011 10:36:38 -0500 Subject: [PATCH 110/214] Added missing mplot3d/offset_demo.py example --- examples/mplot3d/offset_demo.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 examples/mplot3d/offset_demo.py diff --git a/examples/mplot3d/offset_demo.py b/examples/mplot3d/offset_demo.py new file mode 100644 index 000000000000..3edb9cbff8bc --- /dev/null +++ b/examples/mplot3d/offset_demo.py @@ -0,0 +1,26 @@ +from mpl_toolkits.mplot3d import Axes3D +import matplotlib.pyplot as plt +import numpy as np + +# This example demonstrates mplot3d's offset text display. +# As one rotates the 3D figure, the offsets should remain oriented +# same way as the axis label, and should also be located "away" +# from the center of the plot. +# +# This demo triggers the display of the offset text for the x and +# y axis by adding 1e5 to X and Y. Anything less would not +# automatically trigger it. + +fig = plt.figure() +ax = fig.gca(projection='3d') +X, Y = np.mgrid[0:6*np.pi:0.25, 0:4*np.pi:0.25] +Z = np.sqrt(np.abs(np.cos(X) + np.cos(Y))) + +surf = ax.plot_surface(X + 1e5, Y + 1e5, Z, cmap='autumn', cstride=2, rstride=2) +ax.set_xlabel("X-Label") +ax.set_ylabel("Y-Label") +ax.set_zlabel("Z-Label") +ax.set_zlim(0, 2) + +plt.show() + From ca5da7b8438d3fce3fff35f709273af883764cdb Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Mon, 29 Aug 2011 09:37:57 -1000 Subject: [PATCH 111/214] whats_new.rst: a few edits and additions for v1.1 --- doc/users/whats_new.rst | 55 +++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index be38cc1bbc9c..4fc68d88d661 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -7,6 +7,10 @@ What's new in matplotlib This page just covers the highlights -- for the full story, see the `CHANGELOG `_ +.. note:: + Matplotlib version 1.1 is the last major release compatible with Python + versions 2.4 to 2.7. The next major release will support + versions 2.6, 2.7, and 3.1 and higher. .. _whats-new-1-1: @@ -16,16 +20,15 @@ new in matplotlib-1.1 Animation --------- -Ryan May invested significant effort to create a backend-independent +Ryan May has written a backend-independent framework for creating animated figures. The :mod:`~matplotlib.animation` -module is intended to replace the difficult-to-understand, -backend-specific examples that used to exist in the :ref:`examples-index` -listings. +module is intended to replace the +backend-specific examples formerly in the :ref:`examples-index` +listings. Examples using the new framework are in +:ref:`animation-examples-index`. -This framework should be considered a beta feature for matplotlib, but -we highly encourage users to try it out and provide feedback. - -Check out the :ref:`animation-examples-index` and try them out! +This should be considered as a beta release of the framework; +please try it and provide feedback. Tight Layout @@ -42,19 +45,28 @@ so that the axis labels do not overlap with neighboring subplots. A :ref:`plotting-guide-tight-layout` has been created to show how to use this new tool. -Full IPython 0.11 compatibility -------------------------------- +PyQT4, PySide, and IPython +-------------------------- + +Gerald Storer made the Qt4 backend compatible with PySide as +well as PyQT4. At present, however, PySide does not support +the PyOS_InputHook mechanism for handling gui events while +waiting for text input, so it cannot be used with the new +version 0.11 of `IPython `_. Until this +feature appears in PySide, IPython users should use +the PyQT4 wrapper for QT4, which remains the matplotlib default. + +An rcParam entry, "backend.qt4", has been added to allow users +to select PyQt4, PyQt4v2, or PySide. The latter two use the +Version 2 Qt API. In most cases, users can ignore this rcParam +variable; it is available to aid in testing, and to provide control +for users who are embedding matplotlib in a PyQt4 or PySide app. -The `IPython `_ team has recently released v0.11 of -their interactive python shell. The matplotlib and IPython teams worked -to ensure that our packages work well together. This release of matplotlib -is fully compatible with ipython. Legend ------ -Jae-Joon Lee has also been working on revamping how plot legends are handled -in matplotlib. This has resulted in some immediate enhancements. First, +Jae-Joon Lee has improved plot legends. First, legends for complex plots such as :meth:`~matplotlib.pyplot.stem` plots will now display correctly. Second, the 'best' placement of a legend has been improved in the presence of NANs. @@ -130,18 +142,25 @@ Other improvements * An error in the Hammer projection has been fixed. * *clabel* for :meth:`~matplotlib.pyplot.contour` now accepts a callable. - Thanks to Daniel Hyams for the original patch! + Thanks to Daniel Hyams for the original patch. * Jae-Joon Lee added the :class:`~mpl_toolkits.axes_grid1.axes_divider.HBox` and :class:`~mpl_toolkits.axes_grid1.axes_divider.VBox` classes. -* Christoph Gohike improved memory usage in :meth:`~matplotlib.pyplot.imshow`. +* Christoph Gohlke reduced memory usage in :meth:`~matplotlib.pyplot.imshow`. * :meth:`~matplotlib.pyplot.scatter` now accepts empty inputs. * The behavior for 'symlog' scale has been fixed, but this may result in some minor changes to existing plots. +* Peter Butterworth added named figure support to + :func:`~matplotlib.pyplot.figure`. + +* Michiel de Hoon has modified the MacOSX backend to make + its interactive behavior consistent with the other backends. + +* Many bug fixes and documentation improvements. .. _whats-new-1-0: From 199d7734a2d1197fbaabdabe3d1970aaea637195 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Mon, 29 Aug 2011 14:09:08 -1000 Subject: [PATCH 112/214] CHANGELOG: add a few more notes --- CHANGELOG | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2e3bb1e70389..9f5c700bafaa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,6 +29,14 @@ Significant revisions to the documentation as well. - BVR +2011-07-07 Added compatibility with IPython strategy for picking + a version of Qt4 support, and an rcParam for making + the choice explicitly: backend.qt4. - EF + +2011-07-07 Modified AutoMinorLocator to improve automatic choice of + the number of minor intervals per major interval, and + to allow one to specify this number via a kwarg. - EF + 2011-06-28 3D versions of scatter, plot, plot_wireframe, plot_surface, bar3d, and some other functions now support empty inputs. - BVR @@ -39,10 +47,16 @@ 2011-06-22 Add axes.labelweight parameter to set font weight to axis labels - MGD. +2011-06-20 Add pause function to pyplot. - EF + 2011-06-16 Added *bottom* keyword parameter for the stem command. Also, implemented a legend handler for the stem plot. - JJL +2011-06-16 Added legend.frameon rcParams. - Mike Kaufman + +2011-05-31 Made backend_qt4 compatible with PySide . - Gerald Storer + 2011-04-17 Disable keyboard auto-repeat in qt4 backend by ignoring key events resulting from auto-repeat. This makes constrained zoom/pan work. - EF From d01ab8c3ca2b5fe6a5b26b8890d3d23f1be94507 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Tue, 30 Aug 2011 12:30:16 +0900 Subject: [PATCH 113/214] modify tight_layout section of what's new to include a demo --- doc/users/whats_new.rst | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index be38cc1bbc9c..71822fe4d66a 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -35,9 +35,38 @@ A frequent issue raised by users of matplotlib is the lack of a layout engine to nicely space out elements of the plots. While matplotlib still adheres to the philosphy of giving users complete control over the placement of plot elements, Jae-Joon Lee created the :mod:`~matplotlib.tight_layout` -module to address the most common layout issues. +module and introduced a new +command :func:`~matplotlib.pyplot.tight_layout` +to address the most common layout issues. -:mod:`~matplotlib.tight_layout` will adjust the spacing between subplots +.. plot:: + + plt.rcParams['savefig.facecolor'] = "0.8" + plt.rcParams['figure.figsize'] = 4, 3 + + fig, axes_list = plt.subplots(2, 1) + for ax in axes_list.flat: + ax.set(xlabel="x-label", ylabel="y-label", title="before tight_layout") + ax.locator_params(nbins=3) + + plt.show() + + plt.rcParams['savefig.facecolor'] = "0.8" + plt.rcParams['figure.figsize'] = 4, 3 + + fig, axes_list = plt.subplots(2, 1) + for ax in axes_list.flat: + ax.set(xlabel="x-label", ylabel="y-label", title="after tight_layout") + ax.locator_params(nbins=3) + + plt.tight_layout() + plt.show() + +The usage of this functionality can be as simple as :: + + plt.tight_layout() + +and it will adjust the spacing between subplots so that the axis labels do not overlap with neighboring subplots. A :ref:`plotting-guide-tight-layout` has been created to show how to use this new tool. From e21cab4c210dd6204befd68be1ccdea6e3a6cd7d Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 30 Aug 2011 11:03:49 -0400 Subject: [PATCH 114/214] Fix minor typo in What's New doc --- doc/users/whats_new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 2cfd92f8ea3a..e91d675a661b 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -142,7 +142,7 @@ The list of available markers for :meth:`~matplotlib.pyplot.plot` and :meth:`~matplotlib.pyplot.scatter` has now been merged. While they were mostly similar, some markers existed for one function, but not the other. This merge did result in a conflict for the 'd' diamond -marker. Now, 'd' will be interpreated to always mean "thin" diamond +marker. Now, 'd' will be interpreted to always mean "thin" diamond while 'D' will mean "regular" diamond. Thanks to Michael Droettboom for this effort. From f50265f5082622afe38dbb32cba2751151cf0a05 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Wed, 31 Aug 2011 01:08:31 +0900 Subject: [PATCH 115/214] patches.py: add Style.register classmethod --- lib/matplotlib/patches.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 36593d7a95bf..2b1ac987a5a6 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1601,6 +1601,15 @@ def pprint_styles(klass): return _pprint_styles(klass._style_list) + @classmethod + def register(klass, name, style): + """ + Register a new style. + """ + + if not issubclass(style, klass._Base): + raise ValueError("%s must be a subclass of %s" % (style, klass._Base)) + klass._style_list[name] = style class BoxStyle(_Style): From 497681c2ab6856d10ec180c0dd5f8d12296e05c6 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 30 Aug 2011 13:47:36 -0400 Subject: [PATCH 116/214] Implements a new version of symlog that is smooth around linthresh contributed by ssyr. Also includes a cleaner implementation of the symlog ticker. Closes #396. --- doc/users/whats_new.rst | 3 +- examples/pylab_examples/symlog_demo.py | 2 +- lib/matplotlib/scale.py | 72 +- .../baseline_images/test_axes/symlog.pdf | Bin 7255 -> 7059 bytes .../baseline_images/test_axes/symlog.png | Bin 20495 -> 19767 bytes .../baseline_images/test_axes/symlog.svg | 954 ++-- .../baseline_images/test_axes/symlog2.pdf | Bin 14405 -> 15671 bytes .../baseline_images/test_axes/symlog2.png | Bin 57010 -> 57933 bytes .../baseline_images/test_axes/symlog2.svg | 4005 ++++++++++------- lib/matplotlib/ticker.py | 109 +- 10 files changed, 3001 insertions(+), 2144 deletions(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index e91d675a661b..587964e7a67c 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -181,7 +181,8 @@ Other improvements * :meth:`~matplotlib.pyplot.scatter` now accepts empty inputs. * The behavior for 'symlog' scale has been fixed, but this may result - in some minor changes to existing plots. + in some minor changes to existing plots. This work was refined by + ssyr. * Peter Butterworth added named figure support to :func:`~matplotlib.pyplot.figure`. diff --git a/examples/pylab_examples/symlog_demo.py b/examples/pylab_examples/symlog_demo.py index 4b2ac1000b09..276c2e724c6e 100755 --- a/examples/pylab_examples/symlog_demo.py +++ b/examples/pylab_examples/symlog_demo.py @@ -21,7 +21,7 @@ subplot(313) plot(x, np.sin(x / 3.0)) xscale('symlog') -yscale('symlog') +yscale('symlog', linthreshy=0.015) grid(True) ylabel('symlog both') diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index c8f816eeab97..c8d20c21667b 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -312,6 +312,33 @@ class SymmetricalLogScale(ScaleBase): name = 'symlog' class SymmetricalLogTransform(Transform): + input_dims = 1 + output_dims = 1 + is_separable = True + + def __init__(self, base, linthresh): + Transform.__init__(self) + self.base = base + self.linthresh = linthresh + self._log_base = np.log(base) + self._linadjust = (np.log(linthresh) / self._log_base) / linthresh + + def transform(self, a): + a = np.asarray(a) + sign = np.sign(a) + masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) + log = sign * self.linthresh * (1 + ma.log(np.abs(masked) / self.linthresh)) + if masked.mask.any(): + return np.asarray(ma.where(masked.mask, + a, + log)) + else: + return np.asarray(log) + + def inverted(self): + return SymmetricalLogScale.InvertedSymmetricalLogTransform(self.base, self.linthresh) + + class InvertedSymmetricalLogTransform(Transform): input_dims = 1 output_dims = 1 is_separable = True @@ -319,51 +346,22 @@ class SymmetricalLogTransform(Transform): def __init__(self, base, linthresh): Transform.__init__(self) self.base = base - self.linthresh = abs(linthresh) + self.linthresh = linthresh self._log_base = np.log(base) - logb_linthresh = np.log(linthresh) / self._log_base - self._linadjust = 1.0 - logb_linthresh - self._linscale = 1.0 / linthresh + self._log_linthresh = np.log(linthresh) / self._log_base + self._linadjust = linthresh / (np.log(linthresh) / self._log_base) def transform(self, a): a = np.asarray(a) sign = np.sign(a) masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) + exp = sign * self.linthresh * ma.exp(sign * masked / self.linthresh - 1) if masked.mask.any(): - log = sign * (ma.log(np.abs(masked)) / self._log_base + self._linadjust) - return np.asarray(ma.where(masked.mask, a * self._linscale, log)) + return np.asarray(ma.where(masked.mask, + a, + exp)) else: - return sign * (np.log(np.abs(a)) / self._log_base + self._linadjust) - - def inverted(self): - return SymmetricalLogScale.InvertedSymmetricalLogTransform( - self.base, self.linthresh) - - class InvertedSymmetricalLogTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - - def __init__(self, base, linthresh): - Transform.__init__(self) - self.base = base - self.linthresh = linthresh - log_base = np.log(base) - logb_linthresh = np.log(linthresh) / log_base - self._linadjust = 1.0 - logb_linthresh - - def transform(self, a): - a = np.asarray(a) - sign = np.sign(a) - masked = ma.masked_inside(a, -1.0, 1.0, copy=False) - result = np.where((a >= -1.0) & (a <= 1.0), - a * self.linthresh, - sign * np.power(self.base, np.abs(a - sign * self._linadjust))) - return result - - def inverted(self): - return SymmetricalLogScale.SymmetricalLogTransform( - self.base, self.linthresh) + return np.asarray(exp) def __init__(self, axis, **kwargs): """ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf b/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf index acb01e37ad2d651257bc1340ecd3d7aeeb4bced5..87faf62b7cb35207c0d801e6424aab330cddecfd 100644 GIT binary patch delta 2449 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.png b/lib/matplotlib/tests/baseline_images/test_axes/symlog.png index 4cef1a64e5ccdd546a6f6bb217040a2e5de1015d..3e79b600c51772e72b12309573e85c43b505c549 100644 GIT binary patch literal 19767 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%0DemLMUK?neIgfR5`$F0Het;Yz>$JY z?mTC9h;%RHmf!7sQ*}&DT_jotTg@SRCrP;piIj|7&Ftg|IDWXt?_poULj{OOy}0P! zvyHuZaA+NTWL#om4m>sDaRg)%arsCips&>O^{obBfQ@9EF=%L^3yl~4J`ki!6(hWQ zUbz3$0PN*dNRjr@fJZjej6a8GB=8CewT&y-sey;-du|z`nkrie!iuYiw9>5&o|~Yh zrG*Ddzh&0b5i%V}E%EI#yZz#imjn$f>~^-d1h;FTV8VX$*MjF;g%h&_FE!z~Nw`2^Bg()sQp8c-0@$&!4x_mzw3eU0V{_^Fhw{fkvx|;ODJ)&Nf%7Ft1KD>XA zR3?=}SrIm-X~fR$8=MGjFz}%Hg?)geN5Bww&U}5b0#z{mY$u#L`YtBm-@JKaGhGKs zD=E*J5)q+3VE@&jqUiI>TN6;n638aws|9x60JO32Kn*5|$Q8EZ22w*R6Qva{u|(>w z=pWV4xzK}>9{wuXiU&#^n7N(I>D0*!#sxekIMqJ-UE=SsuRpFdXvRN{n0ubGOo@kDY*`%SjXi8YhmrhY(5_CJaB*$AWF=3 zP=F~f;7)GUCmrCn4j*~f9(<|gbfk2;*HC~iD8)1YyaK#g0il&0)NMlo()M9$&S)DV z;f9A~ICMOd_g(4M-D3&;VK#QG=j!n^R7W#}{qYB6bT2<#$U4XV_Jl8c;4gDQ<7&~L z8!*|R8HNXNV2c~JC8;>?UAcNyiQv)epRJnWee2*Is4q(1+J@G&AS;Iy(<3r+aM0%- zF;q59EZHwleug1*CYT2Dg5P_v!j@MgK6KErrciGm_1os=>9Lkr!FP@h4iwD?))9er zSC`h-Vym!Z&~`0Rf+i+wWuUCS7^z^I8?5PPqrG1X^|vv2IGM*(?-;tR&gh4;%NT&1 zxd%vDNV4sxj)3)S4Ia%Yh9((hT);pM2-hr%s(3bCqx>61Y0mJCr8cQ+p9MR7WSPxPDy;3J2{ypRBMM zIA0j*ZR&HDp$nDQ*VjiL7E>WoVXe={!_xs-J241l?h?%sPAf*(K_Yhws&>-T)2}tl zM-BMR*CBQ2AgF#EKqzYz1 zb`k6H*rh%fLWjv838p%*)m^U7T>>i%gF?t`bzqADt!F^Vdcf*eTe!UrJiR~^COUTE zv(gLO_MUg)C&U6by&*UeK06e{3|$0RrwkiUq0FX!KfCn%K4<=nnyALS+}!6Hnwo_r zC1+cq)_-l#D>d%%V@Js&cdX_HUg}s`;eWVFP!vOwzz`9QW~7BfcxI;hxaU@9F)ZK- z2^R>%bYKaFe?^_VTmZ_cWcrAH&leZrF&3q;srql!Nu{Vdg1^uK;*|Kyjw`ac^G0B? z|J!%(E=VP;1gtrJLJUnC;vuUk<-t-v0>x)HJaea0oym$t$OsA_LfpYUt-v#1+}zx< zPQSuIO8=#i5Zoa-;tonGaI*@`5A%ToY49kAMejC7+{)m&k_s0NQe_*?sfreX0yu;b zfu9?@kI6EFs$}G4KO~pn=gXgu$@*tM|K~0KZ@Bc+4tcb8%G=_6?`&j7uvb(SiY}Sm G`Tqd=LDu*H literal 20495 zcmeIacRbd8`#+9|h$JnAvnYEM5;Dr(dt{Fa2`M96A&HFB%1UHp@4X|6GENzhJx?<$ zo8R$1UH9j{Kc9PiKfmvPzsKX}ab4GWo$vEKUh_Df$Mbj|Z+{gfX>w8;Qan67a#xqlYP9&X-W4wf?KX{!aOs2NJQ%`c{jq3IMSXJud>d6ZyRU5UW zN_01#R}{~B7uj4m=3BucNfV^bo@POMno_q)r8V_D*F~bvS7*vuC;FSjzQl>1k@Y_o z`Sn}Ya7^^lw6oioVPRaA_>4zS?C|%~q`r3upka6y?0IOBPqCHvUdU%2IT0azcv&-} zkgt!#@$uoq_yQ>j@^wH(4EgALNq}5jcY~S|`C5|bg?#+~m;N7y32P%LmbAUQ+CI7b zY~o3Izd`L%&5r$`L+^PxA{f87lQ1clx-Lac>vl|b8_ihMVZCkUITC?@tcDC;Mk(MuC@&s7mijj-dAzU9bGSu$h zPnn&Y(^OG;zrVNRRA#60f;OJB~ytI*-nkv

J}s0%`eDOMayePq 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 diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg b/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg index 5410df6caa06..990b1d32e278 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg @@ -35,14 +35,14 @@ z +M72 90.2178 +L89.856 104.372 +L107.712 137.236 +L143.424 278.289 +L179.136 339.46 +L232.704 378.59 +L286.272 378.59 +L500.544 378.59" style="fill:none;stroke:#0000ff;"/> @@ -1179,20 +1161,20 @@ L-2 0" id="m120ec220f0"/> @@ -1201,20 +1183,20 @@ L-2 0" id="m120ec220f0"/> @@ -1223,20 +1205,20 @@ L-2 0" id="m120ec220f0"/> @@ -1245,20 +1227,20 @@ L-2 0" id="m120ec220f0"/> @@ -1267,20 +1249,20 @@ L-2 0" id="m120ec220f0"/> @@ -1289,20 +1271,20 @@ L-2 0" id="m120ec220f0"/> @@ -1311,20 +1293,20 @@ L-2 0" id="m120ec220f0"/> @@ -1333,20 +1315,20 @@ L-2 0" id="m120ec220f0"/> @@ -1355,20 +1337,20 @@ L-2 0" id="m120ec220f0"/> @@ -1377,20 +1359,20 @@ L-2 0" id="m120ec220f0"/> @@ -1399,20 +1381,20 @@ L-2 0" id="m120ec220f0"/> @@ -1421,20 +1403,20 @@ L-2 0" id="m120ec220f0"/> @@ -1443,20 +1425,20 @@ L-2 0" id="m120ec220f0"/> @@ -1465,20 +1447,20 @@ L-2 0" id="m120ec220f0"/> @@ -1487,20 +1469,20 @@ L-2 0" id="m120ec220f0"/> @@ -1509,20 +1491,20 @@ L-2 0" id="m120ec220f0"/> @@ -1531,20 +1513,20 @@ L-2 0" id="m120ec220f0"/> @@ -1553,20 +1535,20 @@ L-2 0" id="m120ec220f0"/> @@ -1575,20 +1557,20 @@ L-2 0" id="m120ec220f0"/> @@ -1597,20 +1579,20 @@ L-2 0" id="m120ec220f0"/> @@ -1619,20 +1601,20 @@ L-2 0" id="m120ec220f0"/> @@ -1641,20 +1623,20 @@ L-2 0" id="m120ec220f0"/> @@ -1663,20 +1645,20 @@ L-2 0" id="m120ec220f0"/> @@ -1685,20 +1667,20 @@ L-2 0" id="m120ec220f0"/> @@ -1707,20 +1689,20 @@ L-2 0" id="m120ec220f0"/> @@ -1729,20 +1711,20 @@ L-2 0" id="m120ec220f0"/> @@ -1751,20 +1733,20 @@ L-2 0" id="m120ec220f0"/> @@ -1773,20 +1755,20 @@ L-2 0" id="m120ec220f0"/> @@ -1795,20 +1777,20 @@ L-2 0" id="m120ec220f0"/> @@ -1817,20 +1799,20 @@ L-2 0" id="m120ec220f0"/> @@ -1839,20 +1821,20 @@ L-2 0" id="m120ec220f0"/> @@ -1861,20 +1843,20 @@ L-2 0" id="m120ec220f0"/> @@ -1883,20 +1865,20 @@ L-2 0" id="m120ec220f0"/> @@ -1905,20 +1887,20 @@ L-2 0" id="m120ec220f0"/> @@ -1927,20 +1909,20 @@ L-2 0" id="m120ec220f0"/> @@ -1949,20 +1931,20 @@ L-2 0" id="m120ec220f0"/> @@ -1971,20 +1953,20 @@ L-2 0" id="m120ec220f0"/> @@ -1993,20 +1975,20 @@ L-2 0" id="m120ec220f0"/> @@ -2015,20 +1997,20 @@ L-2 0" id="m120ec220f0"/> @@ -2037,20 +2019,20 @@ L-2 0" id="m120ec220f0"/> @@ -2059,20 +2041,20 @@ L-2 0" id="m120ec220f0"/> @@ -2081,42 +2063,20 @@ L-2 0" id="m120ec220f0"/> - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog2.pdf b/lib/matplotlib/tests/baseline_images/test_axes/symlog2.pdf index d4ebdd05f3a164a51806df78245d890f6bf040c2..78376b2b5405abea1e8b4000847dafb4784a3fc1 100644 GIT binary patch delta 11020 zcmZWvbzD?k*A @@ -1157,20 +1139,20 @@ L-2 0" id="m120ec220f0"/> @@ -50,46 +50,46 @@ L500.544 367.724" style="fill:none;stroke:#0000ff;"/> +L0 -4" id="ma5e77ffbc8"/> - + +L0 4" id="mf230157f8e"/> - + - @@ -99,52 +99,52 @@ Q19.5312 -74.2188 31.7812 -74.2188" id="BitstreamVeraSans-Roman-30"/> - +M31.7812 66.4062 +Q24.1719 66.4062 20.3281 58.9062 +Q16.5 51.4219 16.5 36.375 +Q16.5 21.3906 20.3281 13.8906 +Q24.1719 6.39062 31.7812 6.39062 +Q39.4531 6.39062 43.2812 13.8906 +Q47.125 21.3906 47.125 36.375 +Q47.125 51.4219 43.2812 58.9062 +Q39.4531 66.4062 31.7812 66.4062 +M31.7812 74.2188 +Q44.0469 74.2188 50.5156 64.5156 +Q56.9844 54.8281 56.9844 36.375 +Q56.9844 17.9688 50.5156 8.26562 +Q44.0469 -1.42188 31.7812 -1.42188 +Q19.5312 -1.42188 13.0625 8.26562 +Q6.59375 17.9688 6.59375 36.375 +Q6.59375 54.8281 13.0625 64.5156 +Q19.5312 74.2188 31.7812 74.2188" id="BitstreamVeraSans-Roman-30"/> + + +L0 -4" id="ma5e77ffbc8"/> - + +L0 4" id="mf230157f8e"/> - + - @@ -154,41 +154,41 @@ z + +L0 -4" id="ma5e77ffbc8"/> - + +L0 4" id="mf230157f8e"/> - + - + @@ -199,25 +199,25 @@ z +L0 -4" id="ma5e77ffbc8"/> - + +L0 4" id="mf230157f8e"/> - + - - @@ -1135,20 +1117,20 @@ L-2 0" id="m120ec220f0"/> + @@ -228,50 +228,50 @@ L0 4" id="m3c2eaff896"/> +L0 -4" id="ma5e77ffbc8"/> - + +L0 4" id="mf230157f8e"/> - + - - - +L7.32812 8.29688 +Q12.9375 14.1094 22.625 23.8906 +Q32.3281 33.6875 34.8125 36.5312 +Q39.5469 41.8438 41.4219 45.5312 +Q43.3125 49.2188 43.3125 52.7812 +Q43.3125 58.5938 39.2344 62.25 +Q35.1562 65.9219 28.6094 65.9219 +Q23.9688 65.9219 18.8125 64.3125 +Q13.6719 62.7031 7.8125 59.4219 +L7.8125 69.3906 +Q13.7656 71.7812 18.9375 73 +Q24.125 74.2188 28.4219 74.2188 +Q39.75 74.2188 46.4844 68.5469 +Q53.2188 62.8906 53.2188 53.4219 +Q53.2188 48.9219 51.5312 44.8906 +Q49.8594 40.875 45.4062 35.4062 +Q44.1875 33.9844 37.6406 27.2188 +Q31.1094 20.4531 19.1875 8.29688" id="BitstreamVeraSans-Roman-32"/> + + @@ -282,25 +282,25 @@ Q31.1094 -20.4531 19.1875 -8.29688" id="BitstreamVeraSans-Roman-32"/> +L0 -4" id="ma5e77ffbc8"/> - + +L0 4" id="mf230157f8e"/> - + - @@ -353,141 +341,113 @@ z + @@ -313,38 +313,26 @@ L0 4" id="m3c2eaff896"/> +L4 0" id="m61f3b1459c"/> - + +L-4 0" id="m947fe6afd9"/> - + - - - - - - - - - + + + +L4 0" id="m61f3b1459c"/> - + +L-4 0" id="m947fe6afd9"/> - + - - - - - - - - - - - - - - - - - - - - - - - - + - @@ -1113,20 +1095,20 @@ L-2 0" id="m120ec220f0"/> + + - @@ -1091,20 +1073,20 @@ L-2 0" id="m120ec220f0"/> +L4 0" id="m61f3b1459c"/> - + + - +L-4 0" id="m947fe6afd9"/> - + + - @@ -1069,20 +1051,20 @@ L-2 0" id="m120ec220f0"/> - + - + @@ -1047,20 +1029,20 @@ L-2 0" id="m120ec220f0"/> + - +L4 0" id="m61f3b1459c"/> - + + - @@ -1025,20 +1007,20 @@ L-2 0" id="m120ec220f0"/> +L-4 0" id="m947fe6afd9"/> - + + - - + - @@ -1003,20 +985,20 @@ L-2 0" id="m120ec220f0"/> + + - @@ -981,20 +963,20 @@ L-2 0" id="m120ec220f0"/> +L4 0" id="m61f3b1459c"/> - + + - +L-4 0" id="m947fe6afd9"/> - + + - @@ -959,20 +941,20 @@ L-2 0" id="m120ec220f0"/> - + - + @@ -937,20 +919,20 @@ L-2 0" id="m120ec220f0"/> + - +L4 0" id="m61f3b1459c"/> - + + - @@ -915,20 +897,20 @@ L-2 0" id="m120ec220f0"/> +L-4 0" id="m947fe6afd9"/> - + + - - + - @@ -893,20 +875,20 @@ L-2 0" id="m120ec220f0"/> + + - @@ -871,20 +853,20 @@ L-2 0" id="m120ec220f0"/> +L4 0" id="m61f3b1459c"/> - + + - +L-4 0" id="m947fe6afd9"/> - + + - @@ -849,20 +831,20 @@ L-2 0" id="m120ec220f0"/> - + - + @@ -827,20 +809,20 @@ L-2 0" id="m120ec220f0"/> + - +L4 0" id="m61f3b1459c"/> - + + - @@ -805,20 +787,20 @@ L-2 0" id="m120ec220f0"/> +L-4 0" id="m947fe6afd9"/> - + + - - + - @@ -783,20 +765,20 @@ L-2 0" id="m120ec220f0"/> + + - @@ -761,20 +743,20 @@ L-2 0" id="m120ec220f0"/> +L4 0" id="m61f3b1459c"/> - + + - +L-4 0" id="m947fe6afd9"/> - + + @@ -739,20 +721,20 @@ L-2 0" id="m120ec220f0"/> + + + + + + + + + + + + + + + + + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + +L-2 0" id="mb3d9a378e9"/> - + +L2 0" id="m3504a0cfb8"/> - + - - - - - - - - - - - - - - - - +L-2 0" id="mb3d9a378e9"/> - + ~HbDCU0W7 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

PKoxgb`I>(T{Gb>PnR3x$i6Hl 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 +M131.289 97.8207 +L139.682 95.5003 +L148.472 93.3021 +L157.705 91.224 +L167.436 89.2636 +L177.723 87.4199 +L188.643 85.6909 +L200.277 84.0761 +L213.206 82.513 +L393.257 61.4964 +L404.932 59.8151 +L415.867 58.0181 +L426.156 56.1039 +L435.875 54.0715 +L445.087 51.9199 +L453.85 49.6467 +L459.109 48.166 +L459.109 48.166" style="fill:none;stroke:#0000ff;"/> @@ -411,20 +410,20 @@ L0 2" id="mcf7d3e9266"/> @@ -433,20 +432,20 @@ L0 2" id="mcf7d3e9266"/> @@ -455,20 +454,20 @@ L0 2" id="mcf7d3e9266"/> @@ -477,20 +476,20 @@ L0 2" id="mcf7d3e9266"/> @@ -499,20 +498,20 @@ L0 2" id="mcf7d3e9266"/> @@ -521,20 +520,20 @@ L0 2" id="mcf7d3e9266"/> @@ -543,20 +542,20 @@ L0 2" id="mcf7d3e9266"/> @@ -565,20 +564,20 @@ L0 2" id="mcf7d3e9266"/> @@ -587,20 +586,20 @@ L0 2" id="mcf7d3e9266"/> @@ -609,20 +608,20 @@ L0 2" id="mcf7d3e9266"/> @@ -631,20 +630,20 @@ L0 2" id="mcf7d3e9266"/> @@ -653,20 +652,20 @@ L0 2" id="mcf7d3e9266"/> @@ -675,20 +674,20 @@ L0 2" id="mcf7d3e9266"/> @@ -697,20 +696,20 @@ L0 2" id="mcf7d3e9266"/> @@ -719,20 +718,20 @@ L0 2" id="mcf7d3e9266"/> @@ -741,20 +740,20 @@ L0 2" id="mcf7d3e9266"/> @@ -763,20 +762,20 @@ L0 2" id="mcf7d3e9266"/> @@ -785,20 +784,20 @@ L0 2" id="mcf7d3e9266"/> @@ -807,20 +806,20 @@ L0 2" id="mcf7d3e9266"/> @@ -836,62 +835,62 @@ L518.4 102.786" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 @@ -1760,20 +1759,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1782,20 +1781,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1804,20 +1803,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1826,20 +1825,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1848,20 +1847,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1870,20 +1869,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1892,20 +1891,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1914,20 +1913,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1936,20 +1935,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1958,20 +1957,20 @@ L0 2" id="mcf7d3e9266"/> @@ -1980,20 +1979,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2002,20 +2001,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2024,20 +2023,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2046,20 +2045,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2068,20 +2067,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2090,20 +2089,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2112,20 +2111,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2134,20 +2133,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2156,20 +2155,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2178,20 +2177,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2200,20 +2199,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2222,20 +2221,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2244,20 +2243,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2266,20 +2265,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2288,20 +2287,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2310,20 +2309,20 @@ L0 2" id="mcf7d3e9266"/> @@ -2339,25 +2338,25 @@ L518.4 174.29" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.00000 @@ -3207,20 +3206,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3229,20 +3228,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3251,20 +3250,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3273,20 +3272,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3295,20 +3294,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3317,20 +3316,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3339,20 +3338,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3361,20 +3360,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3383,20 +3382,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3405,20 +3404,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3427,20 +3426,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3449,20 +3448,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3471,20 +3470,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3493,20 +3492,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3515,20 +3514,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3537,20 +3536,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3559,20 +3558,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3581,20 +3580,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3603,20 +3602,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3625,20 +3624,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3647,20 +3646,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3669,20 +3668,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3691,20 +3690,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3713,20 +3712,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3735,20 +3734,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3757,20 +3756,20 @@ L0 2" id="mcf7d3e9266"/> @@ -3786,25 +3785,25 @@ L518.4 245.793" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 @@ -4819,20 +4818,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4841,20 +4840,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4863,20 +4862,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4885,20 +4884,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4907,20 +4906,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4929,20 +4928,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4951,20 +4950,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4973,20 +4972,20 @@ L0 2" id="mcf7d3e9266"/> @@ -4995,20 +4994,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5017,20 +5016,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5039,20 +5038,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5061,20 +5060,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5083,20 +5082,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5105,20 +5104,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5127,20 +5126,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5149,20 +5148,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5171,20 +5170,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5193,20 +5192,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5215,20 +5214,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5237,20 +5236,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5259,20 +5258,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5281,20 +5280,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5303,20 +5302,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5325,20 +5324,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5347,20 +5346,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5369,20 +5368,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5391,20 +5390,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5413,20 +5412,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5435,20 +5434,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5457,20 +5456,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5479,20 +5478,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5501,20 +5500,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5523,20 +5522,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5545,20 +5544,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5567,20 +5566,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5589,20 +5588,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5611,20 +5610,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5633,20 +5632,20 @@ L0 2" id="mcf7d3e9266"/> @@ -5662,25 +5661,25 @@ L518.4 317.297" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 @@ -66,20 +65,20 @@ L72 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;str +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -160,32 +159,32 @@ z @@ -389,20 +388,20 @@ L0 2" id="mcf7d3e9266"/> +M252.432 102.786 +L252.432 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -367,20 +366,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -203,20 +202,20 @@ L295.2 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -229,32 +228,32 @@ L0 4" id="ma3cbfaed43"/> @@ -345,20 +344,20 @@ L0 2" id="mcf7d3e9266"/> +M337.968 102.786 +L337.968 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -323,20 +322,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -271,20 +270,20 @@ L518.4 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -301,20 +300,20 @@ L0 4" id="ma3cbfaed43"/> +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -1738,20 +1737,20 @@ L0 2" id="mcf7d3e9266"/> - +M33.0156 40.375 +Q26.375 40.375 22.4844 35.8281 +Q18.6094 31.2969 18.6094 23.3906 +Q18.6094 15.5312 22.4844 10.9531 +Q26.375 6.39062 33.0156 6.39062 +Q39.6562 6.39062 43.5312 10.9531 +Q47.4062 15.5312 47.4062 23.3906 +Q47.4062 31.2969 43.5312 35.8281 +Q39.6562 40.375 33.0156 40.375 +M52.5938 71.2969 +L52.5938 62.3125 +Q48.875 64.0625 45.0938 64.9844 +Q41.3125 65.9219 37.5938 65.9219 +Q27.8281 65.9219 22.6719 59.3281 +Q17.5312 52.7344 16.7969 39.4062 +Q19.6719 43.6562 24.0156 45.9219 +Q28.375 48.1875 33.5938 48.1875 +Q44.5781 48.1875 50.9531 41.5156 +Q57.3281 34.8594 57.3281 23.3906 +Q57.3281 12.1562 50.6875 5.35938 +Q44.0469 -1.42188 33.0156 -1.42188 +Q20.3594 -1.42188 13.6719 8.26562 +Q6.98438 17.9688 6.98438 36.375 +Q6.98438 53.6562 15.1875 63.9375 +Q23.3906 74.2188 37.2031 74.2188 +Q40.9219 74.2188 44.7031 73.4844 +Q48.4844 72.75 52.5938 71.2969" id="BitstreamVeraSans-Roman-36"/> + + @@ -908,46 +907,46 @@ L518.4 92.8552" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -1716,20 +1715,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -964,25 +963,25 @@ L518.4 82.9241" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -1694,20 +1693,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -999,25 +998,25 @@ L518.4 72.9931" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -1032,25 +1031,25 @@ L518.4 63.0621" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -1672,20 +1671,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -1066,25 +1065,25 @@ L518.4 53.131" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.00000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -1100,25 +1099,25 @@ L518.4 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -1650,20 +1649,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -1163,42 +1162,42 @@ z +M103.496 169.324 +L108.164 166.9 +L113.028 164.626 +L118.114 162.495 +L123.453 160.499 +L129.08 158.635 +L135.038 156.898 +L141.375 155.284 +L148.152 153.789 +L155.44 152.412 +L163.333 151.15 +L171.944 150.001 +L181.426 148.965 +L191.974 148.039 +L203.868 147.223 +L217.498 146.517 +L233.46 145.918 +L252.919 145.421 +L360.554 142.957 +L376.796 142.296 +L390.514 141.52 +L402.4 140.63 +L412.895 139.626 +L422.294 138.507 +L430.809 137.272 +L438.599 135.921 +L445.783 134.452 +L452.456 132.863 +L458.692 131.152 +L464.55 129.316 +L470.081 127.351 +L475.326 125.253 +L480.321 123.017 +L485.097 120.637 +L486.903 119.669 +L486.903 119.669" style="fill:none;stroke:#0000ff;"/> @@ -1211,20 +1210,20 @@ L72 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -1240,32 +1239,32 @@ L0 4" id="ma3cbfaed43"/> @@ -1628,20 +1627,20 @@ L0 2" id="mcf7d3e9266"/> +M176.628 174.29 +L176.628 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -1606,20 +1605,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -1276,32 +1275,32 @@ L0 4" id="ma3cbfaed43"/> @@ -1584,20 +1583,20 @@ L0 2" id="mcf7d3e9266"/> +M272.48 174.29 +L272.48 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -1562,20 +1561,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -1319,20 +1318,20 @@ L295.2 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -1345,32 +1344,32 @@ L0 4" id="ma3cbfaed43"/> @@ -1540,20 +1539,20 @@ L0 2" id="mcf7d3e9266"/> +M317.92 174.29 +L317.92 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -1518,20 +1517,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -1380,32 +1379,32 @@ L0 4" id="ma3cbfaed43"/> @@ -1496,20 +1495,20 @@ L0 2" id="mcf7d3e9266"/> +M413.772 174.29 +L413.772 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -1474,20 +1473,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -1422,20 +1421,20 @@ L518.4 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -1452,20 +1451,20 @@ L0 4" id="ma3cbfaed43"/> +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -3185,20 +3184,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2374,25 +2373,25 @@ L518.4 164.359" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -3163,20 +3162,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2409,25 +2408,25 @@ L518.4 154.428" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -3141,20 +3140,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2444,25 +2443,25 @@ L518.4 144.497" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -2477,25 +2476,25 @@ L518.4 134.566" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -3119,20 +3118,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2511,25 +2510,25 @@ L518.4 124.634" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -2545,25 +2544,25 @@ L518.4 114.703" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -3097,20 +3096,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2608,44 +2607,44 @@ z +M99.6014 240.828 +L103.762 238.364 +L108.091 236.061 +L112.61 233.909 +L117.347 231.9 +L122.333 230.029 +L127.608 228.288 +L133.214 226.674 +L139.206 225.183 +L145.649 223.811 +L152.628 222.555 +L160.244 221.414 +L168.631 220.386 +L177.972 219.469 +L188.515 218.662 +L200.617 217.964 +L214.809 217.375 +L231.974 216.894 +L253.627 216.519 +L364.126 214.969 +L381.288 214.413 +L395.318 213.743 +L407.203 212.958 +L417.515 212.058 +L426.63 211.044 +L434.804 209.915 +L442.222 208.669 +L449.015 207.306 +L455.287 205.823 +L461.119 204.217 +L466.576 202.487 +L471.712 200.627 +L476.567 198.633 +L481.182 196.499 +L485.584 194.22 +L489.803 191.786 +L490.798 191.173 +L490.798 191.173" style="fill:none;stroke:#0000ff;"/> @@ -2658,20 +2657,20 @@ L72 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -2687,32 +2686,32 @@ L0 4" id="ma3cbfaed43"/> @@ -3075,20 +3074,20 @@ L0 2" id="mcf7d3e9266"/> +M163.69 245.793 +L163.69 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -3053,20 +3052,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2723,32 +2722,32 @@ L0 4" id="ma3cbfaed43"/> @@ -3031,20 +3030,20 @@ L0 2" id="mcf7d3e9266"/> +M255.38 245.793 +L255.38 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -3009,20 +3008,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2766,20 +2765,20 @@ L295.2 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -2792,32 +2791,32 @@ L0 4" id="ma3cbfaed43"/> @@ -2987,20 +2986,20 @@ L0 2" id="mcf7d3e9266"/> +M335.02 245.793 +L335.02 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -2965,20 +2964,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2827,32 +2826,32 @@ L0 4" id="ma3cbfaed43"/> @@ -2943,20 +2942,20 @@ L0 2" id="mcf7d3e9266"/> +M426.71 245.793 +L426.71 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -2921,20 +2920,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -2869,20 +2868,20 @@ L518.4 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -2899,20 +2898,20 @@ L0 4" id="ma3cbfaed43"/> +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -4797,20 +4796,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -3821,25 +3820,25 @@ L518.4 235.862" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -4775,20 +4774,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -3856,25 +3855,25 @@ L518.4 225.931" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -4753,20 +4752,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -3891,25 +3890,25 @@ L518.4 216" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;s +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -3924,25 +3923,25 @@ L518.4 206.069" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -4731,20 +4730,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -3958,25 +3957,25 @@ L518.4 196.138" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -3992,25 +3991,25 @@ L518.4 186.207" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -4709,20 +4708,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4055,48 +4054,48 @@ z +M91.5644 312.331 +L94.7031 309.718 +L97.9489 307.305 +L101.32 305.076 +L104.836 303.018 +L108.523 301.118 +L112.409 299.367 +L116.531 297.755 +L120.93 296.276 +L125.655 294.923 +L130.772 293.693 +L136.363 292.581 +L142.531 291.584 +L149.421 290.7 +L157.23 289.928 +L166.247 289.265 +L176.91 288.711 +L189.961 288.264 +L206.737 287.923 +L230.123 287.687 +L268.104 287.551 +L367.7 287.265 +L391.184 286.956 +L407.44 286.529 +L419.929 285.987 +L430.094 285.33 +L438.673 284.557 +L446.105 283.67 +L452.668 282.667 +L458.55 281.546 +L463.888 280.305 +L468.781 278.943 +L473.305 277.455 +L477.522 275.835 +L481.48 274.079 +L485.217 272.179 +L488.767 270.125 +L492.156 267.908 +L495.409 265.514 +L498.545 262.931 +L498.835 262.676 +L498.835 262.676" style="fill:none;stroke:#0000ff;"/> @@ -4109,20 +4108,20 @@ L72 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;s +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -4138,32 +4137,32 @@ L0 4" id="ma3cbfaed43"/> @@ -4687,20 +4686,20 @@ L0 2" id="mcf7d3e9266"/> +M136.992 317.297 +L136.992 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -4665,20 +4664,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4174,32 +4173,32 @@ L0 4" id="ma3cbfaed43"/> @@ -4643,20 +4642,20 @@ L0 2" id="mcf7d3e9266"/> +M201.983 317.297 +L201.983 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -4621,20 +4620,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4210,32 +4209,32 @@ L0 4" id="ma3cbfaed43"/> @@ -4599,20 +4598,20 @@ L0 2" id="mcf7d3e9266"/> +M266.975 317.297 +L266.975 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -4577,20 +4576,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4254,20 +4253,20 @@ L295.2 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.00000 +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -4280,32 +4279,32 @@ L0 4" id="ma3cbfaed43"/> @@ -4555,20 +4554,20 @@ L0 2" id="mcf7d3e9266"/> +M323.425 317.297 +L323.425 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -4533,20 +4532,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4316,32 +4315,32 @@ L0 4" id="ma3cbfaed43"/> @@ -4511,20 +4510,20 @@ L0 2" id="mcf7d3e9266"/> +M388.417 317.297 +L388.417 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -4489,20 +4488,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4351,32 +4350,32 @@ L0 4" id="ma3cbfaed43"/> @@ -4467,20 +4466,20 @@ L0 2" id="mcf7d3e9266"/> +M453.408 317.297 +L453.408 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - @@ -4445,20 +4444,20 @@ L0 2" id="mcf7d3e9266"/> + @@ -4393,20 +4392,20 @@ L518.4 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.00000 +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -4423,20 +4422,20 @@ L0 4" id="ma3cbfaed43"/> +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -5697,25 +5696,25 @@ L518.4 307.366" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -5732,25 +5731,25 @@ L518.4 297.434" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -5767,25 +5766,25 @@ L518.4 287.503" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - @@ -5800,25 +5799,25 @@ L518.4 277.572" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 + +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -5834,25 +5833,25 @@ L518.4 267.641" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -5868,25 +5867,25 @@ L518.4 257.71" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.00000 +L4 0" id="m8c2f2e3565"/> - + +L-4 0" id="m5a30142178"/> - + - + @@ -5931,70 +5930,70 @@ z +M203.119 433 +L205.375 425.743 +L207.635 419.189 +L209.914 413.23 +L212.191 407.868 +L214.583 402.803 +L216.936 398.334 +L219.387 394.163 +L221.731 390.588 +L224.126 387.31 +L226.558 384.331 +L229.004 381.65 +L231.759 378.968 +L234.539 376.585 +L237.3 374.499 +L240.46 372.414 +L243.589 370.626 +L246.588 369.137 +L250.065 367.647 +L254.202 366.157 +L258.187 364.966 +L263.065 363.774 +L267.604 362.88 +L273.34 361.986 +L322.796 355.134 +L327.335 354.24 +L332.213 353.048 +L336.198 351.857 +L340.335 350.367 +L343.812 348.877 +L347.365 347.09 +L350.42 345.302 +L353.517 343.217 +L356.228 341.131 +L358.964 338.748 +L361.682 336.066 +L364.351 333.087 +L366.729 330.108 +L369.078 326.83 +L371.381 323.255 +L373.793 319.084 +L376.112 314.615 +L378.342 309.848 +L380.606 304.486 +L382.873 298.527 +L385.122 291.972 +L387.338 284.822 +L389.588 276.778 +L391.772 268.138 +L393.953 258.604 +L396.172 247.879 +L398.346 236.259 +L400.516 223.448 +L402.709 209.148 +L404.898 193.357 +L407.068 176.077 +L409.235 157.01 +L411.412 135.857 +L413.578 112.618 +L415.74 86.9959 +L417.904 58.6924 +L420.07 27.4097 +L421.867 -1 +L421.867 -1" style="fill:none;stroke:#0000ff;"/> @@ -6007,20 +6006,20 @@ L72 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + @@ -6036,1272 +6035,2120 @@ L0 4" id="ma3cbfaed43"/> +M122.335 388.8 +L122.335 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - - - - - - + + + + + + +M172.67 388.8 +L172.67 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - - + + - - + +M223.005 388.8 +L223.005 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - - - + + + + + + + +M273.34 388.8 +L273.34 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - - - - - - + + + + + + + +M295.2 388.8 +L295.2 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - - - - - + + + - +M317.06 388.8 +L317.06 329.214" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000;stroke-dashoffset:0.0;stroke-linecap:butt;stroke-width:0.5;"/> +L0 -4" id="mf319d876e1"/> - + +L0 4" id="m454e1aba8b"/> - + - - + + - + + - - - + - - - - +L0 -4" id="mf319d876e1"/> - + - +L0 4" id="m454e1aba8b"/> - + - - - - - - + + + + + + + + - + + + + +L0 -4" id="mf319d876e1"/> - + + +L0 4" id="m454e1aba8b"/> - + + + + + + + + - - - - + - - - - +L0 -4" id="mf319d876e1"/> - + - +L0 4" id="m454e1aba8b"/> - + - - - - - - + + + + + + + - + + + + +L0 -4" id="mf319d876e1"/> - + + +L0 4" id="m454e1aba8b"/> - + + + + + + + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + + - +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + - + + + - + + + + + + +L0 2" id="m8034f06810"/> - + - +L0 -2" id="m974ea0c1f2"/> - + - + - - +M0 0 +L0 2" id="m8034f06810"/> - - - - - + + - + - - - + + +L0 -2" id="m974ea0c1f2"/> - + +L0 2" id="m8034f06810"/> - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - +M0 0 +L0 -2" id="m974ea0c1f2"/> - - - - - + + - + - - +L0 2" id="m8034f06810"/> - + - + + - +L0 -2" id="m974ea0c1f2"/> - - - - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - +L4 0" id="m8c2f2e3565"/> - + + - +L-4 0" id="m5a30142178"/> - + + - + @@ -7310,34 +8157,34 @@ L-4 0" id="m4cb5fee9ac"/> - + - + - +L4 0" id="m8c2f2e3565"/> - + + - +L-4 0" id="m5a30142178"/> - + + - + diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index bc2e263d83b4..c180e5dbe38d 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -1269,9 +1269,6 @@ def subs(self,subs): else: self._subs = np.asarray(subs)+0.0 - def _set_numticks(self): - self.numticks = 15 # todo; be smart here; this is just for dev - def __call__(self): 'Return the locations of the ticks' b=self._base @@ -1370,48 +1367,101 @@ def __init__(self, transform, subs=[1.0]): self._subs = subs self.numticks = 15 - def _set_numticks(self): - self.numticks = 15 # todo; be smart here; this is just for dev - def __call__(self): 'Return the locations of the ticks' b = self._transform.base t = self._transform.linthresh + # Note, these are untransformed coordinates vmin, vmax = self.axis.get_view_interval() - vmin, vmax = self._transform.transform((vmin, vmax)) - - if vmax + # aaaaaaaaa bbbbb ccccccccc + # + # a) and c) will have ticks at integral log positions. The + # number of ticks needs to be reduced if there are more + # than self.numticks of them. + # + # b) has a tick at 0 and only 0 (we assume t is a small + # number, and the linear segment is just an implementation + # detail and not interesting.) + # + # We could also add ticks at t, but that seems to usually be + # uninteresting. + # + # "simple" mode is when the range falls entirely within (-t, + # t) -- it should just display (vmin, 0, vmax) + + has_a = has_b = has_c = False + if vmin < -t: + has_a = True + if vmax > -t: + has_b = True + if vmax > t: + has_c = True + elif vmin < 0: + if vmax > 0: + has_b = True + if vmax > t: + has_c = True + else: + return [vmin, vmax] + elif vmin < t: + if vmax > t: + has_b = True + has_c = True else: - numdec = (-vmin - lt + 1) + 1 + (vmax - lt + 1) + return [vmin, vmax] else: - numdec = vmax - vmin + 1 + has_c = True - stride = 1 - while numdec/stride+1 > self.numticks: - stride += 1 + def get_log_range(lo, hi): + lo = np.floor(np.log(lo) / np.log(b)) + hi = np.ceil(np.log(hi) / np.log(b)) + return lo, hi - if self._subs is None: - subs = np.arange(2.0, b) + # First, calculate all the ranges, so we can determine striding + if has_a: + if has_b: + a_range = get_log_range(t, -vmin + 1) + else: + a_range = get_log_range(-vmax, -vmin + 1) else: - subs = np.asarray(self._subs) + a_range = (0, 0) - if vmin < 0: - if vmax < 0: - decades = -(b ** np.arange(vmin, vmax + 1, stride)) + if has_c: + if has_b: + c_range = get_log_range(t, vmax + 1) else: - decades = np.asarray(list(-(b ** np.arange(np.floor(lt), np.ceil(-vmin) + stride, stride))[::-1]) + - [0] + - list(b ** np.arange(np.floor(lt), np.ceil(vmax) + stride, stride))) + c_range = get_log_range(vmin, vmax + 1) else: - decades = b ** np.arange(vmin, vmax + 1, stride) + c_range = (0, 0) + + total_ticks = (a_range[1] - a_range[0]) + (c_range[1] - c_range[0]) + if has_b: + total_ticks += 1 + stride = max(np.floor(float(total_ticks) / (self.numticks - 1)), 1) + + decades = [] + if has_a: + decades.extend(-1 * (b ** (np.arange(a_range[0], a_range[1], stride)[::-1]))) + + if has_b: + decades.append(0.0) + + if has_c: + decades.extend(b ** (np.arange(c_range[0], c_range[1], stride))) + + # Add the subticks if requested + if self._subs is None: + subs = np.arange(2.0, b) + else: + subs = np.asarray(self._subs) if len(subs) > 1 or subs[0] != 1.0: ticklocs = [] @@ -1419,6 +1469,7 @@ def __call__(self): ticklocs.extend(subs * decade) else: ticklocs = decades + return self.raise_if_exceeds(np.array(ticklocs)) def view_limits(self, vmin, vmax): From d46b6b73f9db5c1c4b5ae66f13f90bfd2796b9b2 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 30 Aug 2011 15:06:40 -0400 Subject: [PATCH 117/214] Fix Python 2.4 syntax error. --- lib/matplotlib/tests/test_cbook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_cbook.py b/lib/matplotlib/tests/test_cbook.py index 8e0904a7c76b..a49e5c7a41e1 100644 --- a/lib/matplotlib/tests/test_cbook.py +++ b/lib/matplotlib/tests/test_cbook.py @@ -33,7 +33,7 @@ def test_restrict_dict(): from matplotlib.cbook import delete_masked_points as dmp -class Test_delete_masked_points(): +class Test_delete_masked_points: def setUp(self): self.mask1 = [False, False, True, True, False, False] self.arr0 = np.arange(1.0,7.0) From b70fd8191162ccd9bbc8662067daa4a91f436be1 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Wed, 31 Aug 2011 09:08:47 +0200 Subject: [PATCH 118/214] cleanup figure test fixes problem in dates test if this runs afterwards --- lib/matplotlib/tests/test_figure.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index a7cb397d2f43..299efc69ab56 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -1,9 +1,10 @@ import matplotlib from nose.tools import assert_equal -from matplotlib.testing.decorators import image_comparison, knownfailureif +from matplotlib.testing.decorators import image_comparison, knownfailureif, cleanup import matplotlib.pyplot as plt +@cleanup def test_figure_label(): # pyplot figure creation, selection and closing with figure label and number plt.close('all') From 13ecb104ed99d4086fe5e1d83992339c4d040091 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Wed, 31 Aug 2011 06:59:55 -1000 Subject: [PATCH 119/214] show: don't block in scripts under ipython --pylab with ipython v0.11 The reworking of show() in mpl v1.0 and 1.0.1 was intended to be compatible with ipython 0.10.x and with the very different 0.11 development branch. Owing to a bug in the implementation of the pylab-mode detection, however, it was blocking in scripts run under 0.11; but owing to another bug in the qt4agg backend, that backend was not affected in ipython-pylab mode, but was inconsistent in raw ipython. Both of these bugs are fixed in this changeset. In addition, a kwarg is added to show() so that one may force either blocking or non-blocking behavior explicitly. This simplifies the pause() function, and may prove useful in other contexts. --- lib/matplotlib/backend_bases.py | 32 ++++++++++++++++++++++---- lib/matplotlib/backends/backend_qt4.py | 14 ++++------- lib/matplotlib/pyplot.py | 21 ++++++++++------- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 19419264043a..69110fc95350 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -66,9 +66,14 @@ class ShowBase(object): Subclass must override mainloop() method. """ - def __call__(self): + def __call__(self, block=None): """ - Show all figures. + Show all figures. If *block* is not None, then + it is a boolean that overrides all other factors + determining whether show blocks by calling mainloop(). + The other factors are: + it does not block if run inside "ipython --pylab"; + it does not block in interactive mode. """ managers = Gcf.get_all_fig_managers() if not managers: @@ -77,11 +82,28 @@ def __call__(self): for manager in managers: manager.show() - try: - if not self._needmain: # ipython flag + if block is not None: + if block: + self.mainloop() + return + else: return + + # Hack: determine at runtime whether we are + # inside ipython in pylab mode. + from matplotlib import pyplot + try: + ipython_pylab = not pyplot.show._needmain + # IPython versions >= 0.10 tack the _needmain + # attribute onto pyplot.show, and always set + # it to False, when in --pylab mode. except AttributeError: - pass + ipython_pylab = False + + # Leave the following as a separate step in case we + # want to control this behavior with an rcParam. + if ipython_pylab: + return if not is_interactive(): self.mainloop() diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 76ba765508aa..277f0d82f6f3 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -21,7 +21,7 @@ figureoptions = None from qt4_compat import QtCore, QtGui, _getSaveFileName, __version__ - + backend_version = __version__ def fn_name(): return sys._getframe(1).f_code.co_name @@ -55,18 +55,12 @@ def _create_qApp(): qApp = QtGui.QApplication( [" "] ) QtCore.QObject.connect( qApp, QtCore.SIGNAL( "lastWindowClosed()" ), qApp, QtCore.SLOT( "quit()" ) ) - #remember that matplotlib created the qApp - will be used by show() - _create_qApp.qAppCreatedHere = True else: qApp = app - _create_qApp.qAppCreatedHere = False - -_create_qApp.qAppCreatedHere = False class Show(ShowBase): def mainloop(self): - if _create_qApp.qAppCreatedHere: - QtGui.qApp.exec_() + QtGui.qApp.exec_() show = Show() @@ -287,7 +281,7 @@ def __init__( self, canvas, num ): if DEBUG: print 'FigureManagerQT.%s' % fn_name() FigureManagerBase.__init__( self, canvas, num ) self.canvas = canvas - self.window = QtGui.QMainWindow() + self.window = QtGui.QMainWindow() self.window.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.window.setWindowTitle("Figure %d" % num) @@ -335,7 +329,7 @@ def notify_axes_change( fig ): def _show_message(self,s): # Fixes a PySide segfault. self.window.statusBar().showMessage(s) - + def _widgetclosed( self ): if self.window._destroying: return self.window._destroying = True diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 66e758929fc4..f5dd5e1df2cf 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -120,16 +120,23 @@ def switch_backend(newbackend): new_figure_manager, draw_if_interactive, _show = pylab_setup() -def show(): +def show(*args, **kw): """ + When running in ipython with its pylab mode, display all + figures and return to the ipython prompt. + In non-interactive mode, display all figures and block until the figures have been closed; in interactive mode it has no effect unless figures were created prior to a change from non-interactive to interactive mode (not recommended). In that case it displays the figures but does not block. + + A single experimental keyword argument, *block*, may be + set to True or False to override the blocking behavior + described above. """ global _show - _show() + _show(*args, **kw) def isinteractive(): @@ -159,6 +166,9 @@ def pause(interval): This can be used for crude animation. For more complex animation, see :mod:`matplotlib.animation`. + This function is experimental; its behavior may be changed + or extended in a future release. + """ backend = rcParams['backend'] if backend in _interactive_bk: @@ -166,13 +176,8 @@ def pause(interval): if figManager is not None: canvas = figManager.canvas canvas.draw() - was_interactive = isinteractive() - if not was_interactive: - ion() - show() + show(block=False) canvas.start_event_loop(interval) - if not was_interactive: - ioff() return # No on-screen figure is active, so sleep() is all we need. From a1de1f1aecad06a69e580a8a860e67e889665706 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Fri, 2 Sep 2011 11:28:40 +0900 Subject: [PATCH 120/214] set_linestyle can take custom dash styles --- lib/matplotlib/backend_bases.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 69110fc95350..d7c93cbe34ac 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -887,12 +887,22 @@ def set_linewidth(self, w): def set_linestyle(self, style): """ Set the linestyle to be one of ('solid', 'dashed', 'dashdot', - 'dotted'). + 'dotted'). One may specify customized dash styles by providing + a tuple of (offset, dash pairs). For example, the predefiend + linestyles have following values.: + + 'dashed' : (0, (6.0, 6.0)), + 'dashdot' : (0, (3.0, 5.0, 1.0, 5.0)), + 'dotted' : (0, (1.0, 3.0)), """ - try: + + if style in self.dashd.keys(): offset, dashes = self.dashd[style] - except: - raise ValueError('Unrecognized linestyle: %s' % style) + elif isinstance(style, tuple): + offset, dashes = style + else: + raise ValueError('Unrecognized linestyle: %s' % str(style)) + self._linestyle = style self.set_dashes(offset, dashes) From f4de737abaa4490e6ec98073a38f3e12fa1ec690 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 5 Sep 2011 11:35:42 +0900 Subject: [PATCH 121/214] fix a bug in TextToPath.get_glyphs_tex that font_bunch variable is sometimes undefined --- lib/matplotlib/textpath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index 5865dcda408d..d27dff6a2b9a 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -317,9 +317,9 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, #oldfont, seq = None, [] for x1, y1, dvifont, glyph, width in page.text: font_and_encoding = self._ps_fontd.get(dvifont.texname) + font_bunch = self.tex_font_map[dvifont.texname] if font_and_encoding is None: - font_bunch = self.tex_font_map[dvifont.texname] font = FT2Font(str(font_bunch.filename)) for charmap_name, charmap_code in [("ADOBE_CUSTOM", 1094992451), From a3c62fa5795a50a689c12e4726d47ac4fcd51363 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 5 Sep 2011 11:38:09 +0900 Subject: [PATCH 122/214] axisartist: *grid* takes the axis parameter (for now the parameter is ignored) --- lib/mpl_toolkits/axisartist/axislines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index 463752e63f61..965df130127c 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -660,7 +660,7 @@ def get_grid_helper(self): return self._grid_helper - def grid(self, b=None, which='major', **kwargs): + def grid(self, b=None, which='major', axis="both", **kwargs): """ Toggle the gridlines, and optionally set the properties of the lines. """ From 7f55623c84eaa7df7c8c534350ac03a72c32fb83 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Sep 2011 12:15:11 -0400 Subject: [PATCH 123/214] Add some missing LaTeX symbols to the mapping. --- lib/matplotlib/_mathtext_data.py | 1361 +----------------------------- 1 file changed, 14 insertions(+), 1347 deletions(-) diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index 69ec5b63453a..a416c32eda95 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -413,1353 +413,6 @@ r'\combiningdotabove' : ('pncri8a', 26), # for \dot } -# Automatically generated. - -type12uni = { - 'uni24C8' : 9416, - 'aring' : 229, - 'uni22A0' : 8864, - 'uni2292' : 8850, - 'quotedblright' : 8221, - 'uni03D2' : 978, - 'uni2215' : 8725, - 'uni03D0' : 976, - 'V' : 86, - 'dollar' : 36, - 'uni301E' : 12318, - 'uni03D5' : 981, - 'four' : 52, - 'uni25A0' : 9632, - 'uni013C' : 316, - 'uni013B' : 315, - 'uni013E' : 318, - 'Yacute' : 221, - 'uni25DE' : 9694, - 'uni013F' : 319, - 'uni255A' : 9562, - 'uni2606' : 9734, - 'uni0180' : 384, - 'uni22B7' : 8887, - 'uni044F' : 1103, - 'uni22B5' : 8885, - 'uni22B4' : 8884, - 'uni22AE' : 8878, - 'uni22B2' : 8882, - 'uni22B1' : 8881, - 'uni22B0' : 8880, - 'uni25CD' : 9677, - 'uni03CE' : 974, - 'uni03CD' : 973, - 'uni03CC' : 972, - 'uni03CB' : 971, - 'uni03CA' : 970, - 'uni22B8' : 8888, - 'uni22C9' : 8905, - 'uni0449' : 1097, - 'uni20DD' : 8413, - 'uni20DC' : 8412, - 'uni20DB' : 8411, - 'uni2231' : 8753, - 'uni25CF' : 9679, - 'uni306E' : 12398, - 'uni03D1' : 977, - 'uni01A1' : 417, - 'uni20D7' : 8407, - 'uni03D6' : 982, - 'uni2233' : 8755, - 'uni20D2' : 8402, - 'uni20D1' : 8401, - 'uni20D0' : 8400, - 'P' : 80, - 'uni22BE' : 8894, - 'uni22BD' : 8893, - 'uni22BC' : 8892, - 'uni22BB' : 8891, - 'underscore' : 95, - 'uni03C8' : 968, - 'uni03C7' : 967, - 'uni0328' : 808, - 'uni03C5' : 965, - 'uni03C4' : 964, - 'uni03C3' : 963, - 'uni03C2' : 962, - 'uni03C1' : 961, - 'uni03C0' : 960, - 'uni2010' : 8208, - 'uni0130' : 304, - 'uni0133' : 307, - 'uni0132' : 306, - 'uni0135' : 309, - 'uni0134' : 308, - 'uni0137' : 311, - 'uni0136' : 310, - 'uni0139' : 313, - 'uni0138' : 312, - 'uni2244' : 8772, - 'uni229A' : 8858, - 'uni2571' : 9585, - 'uni0278' : 632, - 'uni2239' : 8761, - 'p' : 112, - 'uni3019' : 12313, - 'uni25CB' : 9675, - 'uni03DB' : 987, - 'uni03DC' : 988, - 'uni03DA' : 986, - 'uni03DF' : 991, - 'uni03DD' : 989, - 'uni013D' : 317, - 'uni220A' : 8714, - 'uni220C' : 8716, - 'uni220B' : 8715, - 'uni220E' : 8718, - 'uni220D' : 8717, - 'uni220F' : 8719, - 'uni22CC' : 8908, - 'Otilde' : 213, - 'uni25E5' : 9701, - 'uni2736' : 10038, - 'perthousand' : 8240, - 'zero' : 48, - 'uni279B' : 10139, - 'dotlessi' : 305, - 'uni2279' : 8825, - 'Scaron' : 352, - 'zcaron' : 382, - 'uni21D8' : 8664, - 'egrave' : 232, - 'uni0271' : 625, - 'uni01AA' : 426, - 'uni2332' : 9010, - 'section' : 167, - 'uni25E4' : 9700, - 'Icircumflex' : 206, - 'ntilde' : 241, - 'uni041E' : 1054, - 'ampersand' : 38, - 'uni041C' : 1052, - 'uni041A' : 1050, - 'uni22AB' : 8875, - 'uni21DB' : 8667, - 'dotaccent' : 729, - 'uni0416' : 1046, - 'uni0417' : 1047, - 'uni0414' : 1044, - 'uni0415' : 1045, - 'uni0412' : 1042, - 'uni0413' : 1043, - 'degree' : 176, - 'uni0411' : 1041, - 'K' : 75, - 'uni25EB' : 9707, - 'uni25EF' : 9711, - 'uni0418' : 1048, - 'uni0419' : 1049, - 'uni2263' : 8803, - 'uni226E' : 8814, - 'uni2251' : 8785, - 'uni02C8' : 712, - 'uni2262' : 8802, - 'acircumflex' : 226, - 'uni22B3' : 8883, - 'uni2261' : 8801, - 'uni2394' : 9108, - 'Aring' : 197, - 'uni2260' : 8800, - 'uni2254' : 8788, - 'uni0436' : 1078, - 'uni2267' : 8807, - 'k' : 107, - 'uni22C8' : 8904, - 'uni226A' : 8810, - 'uni231F' : 8991, - 'smalltilde' : 732, - 'uni2201' : 8705, - 'uni2200' : 8704, - 'uni2203' : 8707, - 'uni02BD' : 701, - 'uni2205' : 8709, - 'uni2204' : 8708, - 'Agrave' : 192, - 'uni2206' : 8710, - 'uni2209' : 8713, - 'uni2208' : 8712, - 'uni226D' : 8813, - 'uni2264' : 8804, - 'uni263D' : 9789, - 'uni2258' : 8792, - 'uni02D3' : 723, - 'uni02D2' : 722, - 'uni02D1' : 721, - 'uni02D0' : 720, - 'uni25E1' : 9697, - 'divide' : 247, - 'uni02D5' : 725, - 'uni02D4' : 724, - 'ocircumflex' : 244, - 'uni2524' : 9508, - 'uni043A' : 1082, - 'uni24CC' : 9420, - 'asciitilde' : 126, - 'uni22B9' : 8889, - 'uni24D2' : 9426, - 'uni211E' : 8478, - 'uni211D' : 8477, - 'uni24DD' : 9437, - 'uni211A' : 8474, - 'uni211C' : 8476, - 'uni211B' : 8475, - 'uni25C6' : 9670, - 'uni017F' : 383, - 'uni017A' : 378, - 'uni017C' : 380, - 'uni017B' : 379, - 'uni0346' : 838, - 'uni22F1' : 8945, - 'uni22F0' : 8944, - 'two' : 50, - 'uni2298' : 8856, - 'uni24D1' : 9425, - 'E' : 69, - 'uni025D' : 605, - 'scaron' : 353, - 'uni2322' : 8994, - 'uni25E3' : 9699, - 'uni22BF' : 8895, - 'F' : 70, - 'uni0440' : 1088, - 'uni255E' : 9566, - 'uni22BA' : 8890, - 'uni0175' : 373, - 'uni0174' : 372, - 'uni0177' : 375, - 'uni0176' : 374, - 'bracketleft' : 91, - 'uni0170' : 368, - 'uni0173' : 371, - 'uni0172' : 370, - 'asciicircum' : 94, - 'uni0179' : 377, - 'uni2590' : 9616, - 'uni25E2' : 9698, - 'uni2119' : 8473, - 'uni2118' : 8472, - 'uni25CC' : 9676, - 'f' : 102, - 'ordmasculine' : 186, - 'uni229B' : 8859, - 'uni22A1' : 8865, - 'uni2111' : 8465, - 'uni2110' : 8464, - 'uni2113' : 8467, - 'uni2112' : 8466, - 'mu' : 181, - 'uni2281' : 8833, - 'paragraph' : 182, - 'nine' : 57, - 'uni25EC' : 9708, - 'v' : 118, - 'uni040C' : 1036, - 'uni0113' : 275, - 'uni22D0' : 8912, - 'uni21CC' : 8652, - 'uni21CB' : 8651, - 'uni21CA' : 8650, - 'uni22A5' : 8869, - 'uni21CF' : 8655, - 'uni21CE' : 8654, - 'uni21CD' : 8653, - 'guilsinglleft' : 8249, - 'backslash' : 92, - 'uni2284' : 8836, - 'uni224E' : 8782, - 'uni224D' : 8781, - 'uni224F' : 8783, - 'uni224A' : 8778, - 'uni2287' : 8839, - 'uni224C' : 8780, - 'uni224B' : 8779, - 'uni21BD' : 8637, - 'uni2286' : 8838, - 'uni030F' : 783, - 'uni030D' : 781, - 'uni030E' : 782, - 'uni030B' : 779, - 'uni030C' : 780, - 'uni030A' : 778, - 'uni026E' : 622, - 'uni026D' : 621, - 'six' : 54, - 'uni026A' : 618, - 'uni026C' : 620, - 'uni25C1' : 9665, - 'uni20D6' : 8406, - 'uni045B' : 1115, - 'uni045C' : 1116, - 'uni256B' : 9579, - 'uni045A' : 1114, - 'uni045F' : 1119, - 'uni045E' : 1118, - 'A' : 65, - 'uni2569' : 9577, - 'uni0458' : 1112, - 'uni0459' : 1113, - 'uni0452' : 1106, - 'uni0453' : 1107, - 'uni2562' : 9570, - 'uni0451' : 1105, - 'uni0456' : 1110, - 'uni0457' : 1111, - 'uni0454' : 1108, - 'uni0455' : 1109, - 'icircumflex' : 238, - 'uni0307' : 775, - 'uni0304' : 772, - 'uni0305' : 773, - 'uni0269' : 617, - 'uni0268' : 616, - 'uni0300' : 768, - 'uni0301' : 769, - 'uni0265' : 613, - 'uni0264' : 612, - 'uni0267' : 615, - 'uni0266' : 614, - 'uni0261' : 609, - 'uni0260' : 608, - 'uni0263' : 611, - 'uni0262' : 610, - 'a' : 97, - 'uni2207' : 8711, - 'uni2247' : 8775, - 'uni2246' : 8774, - 'uni2241' : 8769, - 'uni2240' : 8768, - 'uni2243' : 8771, - 'uni2242' : 8770, - 'uni2312' : 8978, - 'ogonek' : 731, - 'uni2249' : 8777, - 'uni2248' : 8776, - 'uni3030' : 12336, - 'q' : 113, - 'uni21C2' : 8642, - 'uni21C1' : 8641, - 'uni21C0' : 8640, - 'uni21C7' : 8647, - 'uni21C6' : 8646, - 'uni21C5' : 8645, - 'uni21C4' : 8644, - 'uni225F' : 8799, - 'uni212C' : 8492, - 'uni21C8' : 8648, - 'uni2467' : 9319, - 'oacute' : 243, - 'uni028F' : 655, - 'uni028E' : 654, - 'uni026F' : 623, - 'uni028C' : 652, - 'uni028B' : 651, - 'uni028A' : 650, - 'uni2510' : 9488, - 'ograve' : 242, - 'edieresis' : 235, - 'uni22CE' : 8910, - 'uni22CF' : 8911, - 'uni219F' : 8607, - 'comma' : 44, - 'uni22CA' : 8906, - 'uni0429' : 1065, - 'uni03C6' : 966, - 'uni0427' : 1063, - 'uni0426' : 1062, - 'uni0425' : 1061, - 'uni0424' : 1060, - 'uni0423' : 1059, - 'uni0422' : 1058, - 'uni0421' : 1057, - 'uni0420' : 1056, - 'uni2465' : 9317, - 'uni24D0' : 9424, - 'uni2464' : 9316, - 'uni0430' : 1072, - 'otilde' : 245, - 'uni2661' : 9825, - 'uni24D6' : 9430, - 'uni2466' : 9318, - 'uni24D5' : 9429, - 'uni219A' : 8602, - 'uni2518' : 9496, - 'uni22B6' : 8886, - 'uni2461' : 9313, - 'uni24D4' : 9428, - 'uni2460' : 9312, - 'uni24EA' : 9450, - 'guillemotright' : 187, - 'ecircumflex' : 234, - 'greater' : 62, - 'uni2011' : 8209, - 'uacute' : 250, - 'uni2462' : 9314, - 'L' : 76, - 'bullet' : 8226, - 'uni02A4' : 676, - 'uni02A7' : 679, - 'cedilla' : 184, - 'uni02A2' : 674, - 'uni2015' : 8213, - 'uni22C4' : 8900, - 'uni22C5' : 8901, - 'uni22AD' : 8877, - 'uni22C7' : 8903, - 'uni22C0' : 8896, - 'uni2016' : 8214, - 'uni22C2' : 8898, - 'uni22C3' : 8899, - 'uni24CF' : 9423, - 'uni042F' : 1071, - 'uni042E' : 1070, - 'uni042D' : 1069, - 'ydieresis' : 255, - 'l' : 108, - 'logicalnot' : 172, - 'uni24CA' : 9418, - 'uni0287' : 647, - 'uni0286' : 646, - 'uni0285' : 645, - 'uni0284' : 644, - 'uni0283' : 643, - 'uni0282' : 642, - 'uni0281' : 641, - 'uni027C' : 636, - 'uni2664' : 9828, - 'exclamdown' : 161, - 'uni25C4' : 9668, - 'uni0289' : 649, - 'uni0288' : 648, - 'uni039A' : 922, - 'endash' : 8211, - 'uni2640' : 9792, - 'uni20E4' : 8420, - 'uni0473' : 1139, - 'uni20E1' : 8417, - 'uni2642' : 9794, - 'uni03B8' : 952, - 'uni03B9' : 953, - 'agrave' : 224, - 'uni03B4' : 948, - 'uni03B5' : 949, - 'uni03B6' : 950, - 'uni03B7' : 951, - 'uni03B0' : 944, - 'uni03B1' : 945, - 'uni03B2' : 946, - 'uni03B3' : 947, - 'uni2555' : 9557, - 'Adieresis' : 196, - 'germandbls' : 223, - 'Odieresis' : 214, - 'space' : 32, - 'uni0126' : 294, - 'uni0127' : 295, - 'uni0124' : 292, - 'uni0125' : 293, - 'uni0122' : 290, - 'uni0123' : 291, - 'uni0120' : 288, - 'uni0121' : 289, - 'quoteright' : 8217, - 'uni2560' : 9568, - 'uni2556' : 9558, - 'ucircumflex' : 251, - 'uni2561' : 9569, - 'uni2551' : 9553, - 'uni25B2' : 9650, - 'uni2550' : 9552, - 'uni2563' : 9571, - 'uni2553' : 9555, - 'G' : 71, - 'uni2564' : 9572, - 'uni2552' : 9554, - 'quoteleft' : 8216, - 'uni2565' : 9573, - 'uni2572' : 9586, - 'uni2568' : 9576, - 'uni2566' : 9574, - 'W' : 87, - 'uni214A' : 8522, - 'uni012F' : 303, - 'uni012D' : 301, - 'uni012E' : 302, - 'uni012B' : 299, - 'uni012C' : 300, - 'uni255C' : 9564, - 'uni012A' : 298, - 'uni2289' : 8841, - 'Q' : 81, - 'uni2320' : 8992, - 'uni2321' : 8993, - 'g' : 103, - 'uni03BD' : 957, - 'uni03BE' : 958, - 'uni03BF' : 959, - 'uni2282' : 8834, - 'uni2285' : 8837, - 'uni03BA' : 954, - 'uni03BB' : 955, - 'uni03BC' : 956, - 'uni2128' : 8488, - 'uni25B7' : 9655, - 'w' : 119, - 'uni0302' : 770, - 'uni03DE' : 990, - 'uni25DA' : 9690, - 'uni0303' : 771, - 'uni0463' : 1123, - 'uni0462' : 1122, - 'uni3018' : 12312, - 'uni2514' : 9492, - 'question' : 63, - 'uni25B3' : 9651, - 'uni24E1' : 9441, - 'one' : 49, - 'uni200A' : 8202, - 'uni2278' : 8824, - 'ring' : 730, - 'uni0195' : 405, - 'figuredash' : 8210, - 'uni22EC' : 8940, - 'uni0339' : 825, - 'uni0338' : 824, - 'uni0337' : 823, - 'uni0336' : 822, - 'uni0335' : 821, - 'uni0333' : 819, - 'uni0332' : 818, - 'uni0331' : 817, - 'uni0330' : 816, - 'uni01C1' : 449, - 'uni01C0' : 448, - 'uni01C3' : 451, - 'uni01C2' : 450, - 'uni2353' : 9043, - 'uni0308' : 776, - 'uni2218' : 8728, - 'uni2219' : 8729, - 'uni2216' : 8726, - 'uni2217' : 8727, - 'uni2214' : 8724, - 'uni0309' : 777, - 'uni2609' : 9737, - 'uni2213' : 8723, - 'uni2210' : 8720, - 'uni2211' : 8721, - 'uni2245' : 8773, - 'B' : 66, - 'uni25D6' : 9686, - 'iacute' : 237, - 'uni02E6' : 742, - 'uni02E7' : 743, - 'uni02E8' : 744, - 'uni02E9' : 745, - 'uni221D' : 8733, - 'uni221E' : 8734, - 'Ydieresis' : 376, - 'uni221C' : 8732, - 'uni22D7' : 8919, - 'uni221A' : 8730, - 'R' : 82, - 'uni24DC' : 9436, - 'uni033F' : 831, - 'uni033E' : 830, - 'uni033C' : 828, - 'uni033B' : 827, - 'uni033A' : 826, - 'b' : 98, - 'uni228A' : 8842, - 'uni22DB' : 8923, - 'uni2554' : 9556, - 'uni046B' : 1131, - 'uni046A' : 1130, - 'r' : 114, - 'uni24DB' : 9435, - 'Ccedilla' : 199, - 'minus' : 8722, - 'uni24DA' : 9434, - 'uni03F0' : 1008, - 'uni03F1' : 1009, - 'uni20AC' : 8364, - 'uni2276' : 8822, - 'uni24C0' : 9408, - 'uni0162' : 354, - 'uni0163' : 355, - 'uni011E' : 286, - 'uni011D' : 285, - 'uni011C' : 284, - 'uni011B' : 283, - 'uni0164' : 356, - 'uni0165' : 357, - 'Lslash' : 321, - 'uni0168' : 360, - 'uni0169' : 361, - 'uni25C9' : 9673, - 'uni02E5' : 741, - 'uni21C3' : 8643, - 'uni24C4' : 9412, - 'uni24E2' : 9442, - 'uni2277' : 8823, - 'uni013A' : 314, - 'uni2102' : 8450, - 'Uacute' : 218, - 'uni2317' : 8983, - 'uni2107' : 8455, - 'uni221F' : 8735, - 'yacute' : 253, - 'uni3012' : 12306, - 'Ucircumflex' : 219, - 'uni015D' : 349, - 'quotedbl' : 34, - 'uni25D9' : 9689, - 'uni2280' : 8832, - 'uni22AF' : 8879, - 'onehalf' : 189, - 'uni221B' : 8731, - 'Thorn' : 222, - 'uni2226' : 8742, - 'M' : 77, - 'uni25BA' : 9658, - 'uni2463' : 9315, - 'uni2336' : 9014, - 'eight' : 56, - 'uni2236' : 8758, - 'multiply' : 215, - 'uni210C' : 8460, - 'uni210A' : 8458, - 'uni21C9' : 8649, - 'grave' : 96, - 'uni210E' : 8462, - 'uni0117' : 279, - 'uni016C' : 364, - 'uni0115' : 277, - 'uni016A' : 362, - 'uni016F' : 367, - 'uni0112' : 274, - 'uni016D' : 365, - 'uni016E' : 366, - 'Ocircumflex' : 212, - 'uni2305' : 8965, - 'm' : 109, - 'uni24DF' : 9439, - 'uni0119' : 281, - 'uni0118' : 280, - 'uni20A3' : 8355, - 'uni20A4' : 8356, - 'uni20A7' : 8359, - 'uni2288' : 8840, - 'uni24C3' : 9411, - 'uni251C' : 9500, - 'uni228D' : 8845, - 'uni222F' : 8751, - 'uni222E' : 8750, - 'uni222D' : 8749, - 'uni222C' : 8748, - 'uni222B' : 8747, - 'uni222A' : 8746, - 'uni255B' : 9563, - 'Ugrave' : 217, - 'uni24DE' : 9438, - 'guilsinglright' : 8250, - 'uni250A' : 9482, - 'Ntilde' : 209, - 'uni0279' : 633, - 'questiondown' : 191, - 'uni256C' : 9580, - 'Atilde' : 195, - 'uni0272' : 626, - 'uni0273' : 627, - 'uni0270' : 624, - 'ccedilla' : 231, - 'uni0276' : 630, - 'uni0277' : 631, - 'uni0274' : 628, - 'uni0275' : 629, - 'uni2252' : 8786, - 'uni041F' : 1055, - 'uni2250' : 8784, - 'Z' : 90, - 'uni2256' : 8790, - 'uni2257' : 8791, - 'copyright' : 169, - 'uni2255' : 8789, - 'uni043D' : 1085, - 'uni043E' : 1086, - 'uni043F' : 1087, - 'yen' : 165, - 'uni041D' : 1053, - 'uni043B' : 1083, - 'uni043C' : 1084, - 'uni21B0' : 8624, - 'uni21B1' : 8625, - 'uni21B2' : 8626, - 'uni21B3' : 8627, - 'uni21B4' : 8628, - 'uni21B5' : 8629, - 'uni21B6' : 8630, - 'uni21B7' : 8631, - 'uni21B8' : 8632, - 'Eacute' : 201, - 'uni2311' : 8977, - 'uni2310' : 8976, - 'uni228F' : 8847, - 'uni25DB' : 9691, - 'uni21BA' : 8634, - 'uni21BB' : 8635, - 'uni21BC' : 8636, - 'uni2017' : 8215, - 'uni21BE' : 8638, - 'uni21BF' : 8639, - 'uni231C' : 8988, - 'H' : 72, - 'uni0293' : 659, - 'uni2202' : 8706, - 'uni22A4' : 8868, - 'uni231E' : 8990, - 'uni2232' : 8754, - 'uni225B' : 8795, - 'uni225C' : 8796, - 'uni24D9' : 9433, - 'uni225A' : 8794, - 'uni0438' : 1080, - 'uni0439' : 1081, - 'uni225D' : 8797, - 'uni225E' : 8798, - 'uni0434' : 1076, - 'X' : 88, - 'uni007F' : 127, - 'uni0437' : 1079, - 'Idieresis' : 207, - 'uni0431' : 1073, - 'uni0432' : 1074, - 'uni0433' : 1075, - 'uni22AC' : 8876, - 'uni22CD' : 8909, - 'uni25A3' : 9635, - 'bar' : 124, - 'uni24BB' : 9403, - 'uni037E' : 894, - 'uni027B' : 635, - 'h' : 104, - 'uni027A' : 634, - 'uni027F' : 639, - 'uni027D' : 637, - 'uni027E' : 638, - 'uni2227' : 8743, - 'uni2004' : 8196, - 'uni2225' : 8741, - 'uni2224' : 8740, - 'uni2223' : 8739, - 'uni2222' : 8738, - 'uni2221' : 8737, - 'uni2220' : 8736, - 'x' : 120, - 'uni2323' : 8995, - 'uni2559' : 9561, - 'uni2558' : 9560, - 'uni2229' : 8745, - 'uni2228' : 8744, - 'udieresis' : 252, - 'uni029D' : 669, - 'ordfeminine' : 170, - 'uni22CB' : 8907, - 'uni233D' : 9021, - 'uni0428' : 1064, - 'uni24C6' : 9414, - 'uni22DD' : 8925, - 'uni24C7' : 9415, - 'uni015C' : 348, - 'uni015B' : 347, - 'uni015A' : 346, - 'uni22AA' : 8874, - 'uni015F' : 351, - 'uni015E' : 350, - 'braceleft' : 123, - 'uni24C5' : 9413, - 'uni0410' : 1040, - 'uni03AA' : 938, - 'uni24C2' : 9410, - 'uni03AC' : 940, - 'uni03AB' : 939, - 'macron' : 175, - 'uni03AD' : 941, - 'uni03AF' : 943, - 'uni0294' : 660, - 'uni0295' : 661, - 'uni0296' : 662, - 'uni0297' : 663, - 'uni0290' : 656, - 'uni0291' : 657, - 'uni0292' : 658, - 'atilde' : 227, - 'Acircumflex' : 194, - 'uni2370' : 9072, - 'uni24C1' : 9409, - 'uni0298' : 664, - 'uni0299' : 665, - 'Oslash' : 216, - 'uni029E' : 670, - 'C' : 67, - 'quotedblleft' : 8220, - 'uni029B' : 667, - 'uni029C' : 668, - 'uni03A9' : 937, - 'uni03A8' : 936, - 'S' : 83, - 'uni24C9' : 9417, - 'uni03A1' : 929, - 'uni03A0' : 928, - 'exclam' : 33, - 'uni03A5' : 933, - 'uni03A4' : 932, - 'uni03A7' : 935, - 'Zcaron' : 381, - 'uni2133' : 8499, - 'uni2132' : 8498, - 'uni0159' : 345, - 'uni0158' : 344, - 'uni2137' : 8503, - 'uni2005' : 8197, - 'uni2135' : 8501, - 'uni2134' : 8500, - 'uni02BA' : 698, - 'uni2033' : 8243, - 'uni0151' : 337, - 'uni0150' : 336, - 'uni0157' : 343, - 'equal' : 61, - 'uni0155' : 341, - 'uni0154' : 340, - 's' : 115, - 'uni233F' : 9023, - 'eth' : 240, - 'uni24BE' : 9406, - 'uni21E9' : 8681, - 'uni2060' : 8288, - 'Egrave' : 200, - 'uni255D' : 9565, - 'uni24CD' : 9421, - 'uni21E1' : 8673, - 'uni21B9' : 8633, - 'hyphen' : 45, - 'uni01BE' : 446, - 'uni01BB' : 443, - 'period' : 46, - 'igrave' : 236, - 'uni01BA' : 442, - 'uni2296' : 8854, - 'uni2297' : 8855, - 'uni2294' : 8852, - 'uni2295' : 8853, - 'colon' : 58, - 'uni2293' : 8851, - 'uni2290' : 8848, - 'uni2291' : 8849, - 'uni032D' : 813, - 'uni032E' : 814, - 'uni032F' : 815, - 'uni032A' : 810, - 'uni032B' : 811, - 'uni032C' : 812, - 'uni231D' : 8989, - 'Ecircumflex' : 202, - 'uni24D7' : 9431, - 'uni25DD' : 9693, - 'trademark' : 8482, - 'Aacute' : 193, - 'cent' : 162, - 'uni0445' : 1093, - 'uni266E' : 9838, - 'uni266D' : 9837, - 'uni266B' : 9835, - 'uni03C9' : 969, - 'uni2003' : 8195, - 'uni2047' : 8263, - 'lslash' : 322, - 'uni03A6' : 934, - 'uni2043' : 8259, - 'uni250C' : 9484, - 'uni2040' : 8256, - 'uni255F' : 9567, - 'uni24CB' : 9419, - 'uni0472' : 1138, - 'uni0446' : 1094, - 'uni0474' : 1140, - 'uni0475' : 1141, - 'uni2508' : 9480, - 'uni2660' : 9824, - 'uni2506' : 9478, - 'uni2502' : 9474, - 'c' : 99, - 'uni2500' : 9472, - 'N' : 78, - 'uni22A6' : 8870, - 'uni21E7' : 8679, - 'uni2130' : 8496, - 'uni2002' : 8194, - 'breve' : 728, - 'uni0442' : 1090, - 'Oacute' : 211, - 'uni229F' : 8863, - 'uni25C7' : 9671, - 'uni229D' : 8861, - 'uni229E' : 8862, - 'guillemotleft' : 171, - 'uni0329' : 809, - 'uni24E5' : 9445, - 'uni011F' : 287, - 'uni0324' : 804, - 'uni0325' : 805, - 'uni0326' : 806, - 'uni0327' : 807, - 'uni0321' : 801, - 'uni0322' : 802, - 'n' : 110, - 'uni2032' : 8242, - 'uni2269' : 8809, - 'uni2268' : 8808, - 'uni0306' : 774, - 'uni226B' : 8811, - 'uni21EA' : 8682, - 'uni0166' : 358, - 'uni203B' : 8251, - 'uni01B5' : 437, - 'idieresis' : 239, - 'uni02BC' : 700, - 'uni01B0' : 432, - 'braceright' : 125, - 'seven' : 55, - 'uni02BB' : 699, - 'uni011A' : 282, - 'uni29FB' : 10747, - 'brokenbar' : 166, - 'uni2036' : 8246, - 'uni25C0' : 9664, - 'uni0156' : 342, - 'uni22D5' : 8917, - 'uni0258' : 600, - 'ugrave' : 249, - 'uni22D6' : 8918, - 'uni22D1' : 8913, - 'uni2034' : 8244, - 'uni22D3' : 8915, - 'uni22D2' : 8914, - 'uni203C' : 8252, - 'uni223E' : 8766, - 'uni02BF' : 703, - 'uni22D9' : 8921, - 'uni22D8' : 8920, - 'uni25BD' : 9661, - 'uni25BE' : 9662, - 'uni25BF' : 9663, - 'uni041B' : 1051, - 'periodcentered' : 183, - 'uni25BC' : 9660, - 'uni019E' : 414, - 'uni019B' : 411, - 'uni019A' : 410, - 'uni2007' : 8199, - 'uni0391' : 913, - 'uni0390' : 912, - 'uni0393' : 915, - 'uni0392' : 914, - 'uni0395' : 917, - 'uni0394' : 916, - 'uni0397' : 919, - 'uni0396' : 918, - 'uni0399' : 921, - 'uni0398' : 920, - 'uni25C8' : 9672, - 'uni2468' : 9320, - 'sterling' : 163, - 'uni22EB' : 8939, - 'uni039C' : 924, - 'uni039B' : 923, - 'uni039E' : 926, - 'uni039D' : 925, - 'uni039F' : 927, - 'I' : 73, - 'uni03E1' : 993, - 'uni03E0' : 992, - 'uni2319' : 8985, - 'uni228B' : 8843, - 'uni25B5' : 9653, - 'uni25B6' : 9654, - 'uni22EA' : 8938, - 'uni24B9' : 9401, - 'uni044E' : 1102, - 'uni0199' : 409, - 'uni2266' : 8806, - 'Y' : 89, - 'uni22A2' : 8866, - 'Eth' : 208, - 'uni266F' : 9839, - 'emdash' : 8212, - 'uni263B' : 9787, - 'uni24BD' : 9405, - 'uni22DE' : 8926, - 'uni0360' : 864, - 'uni2557' : 9559, - 'uni22DF' : 8927, - 'uni22DA' : 8922, - 'uni22DC' : 8924, - 'uni0361' : 865, - 'i' : 105, - 'uni24BF' : 9407, - 'uni0362' : 866, - 'uni263E' : 9790, - 'uni028D' : 653, - 'uni2259' : 8793, - 'uni0323' : 803, - 'uni2265' : 8805, - 'daggerdbl' : 8225, - 'y' : 121, - 'uni010A' : 266, - 'plusminus' : 177, - 'less' : 60, - 'uni21AE' : 8622, - 'uni0315' : 789, - 'uni230B' : 8971, - 'uni21AF' : 8623, - 'uni21AA' : 8618, - 'uni21AC' : 8620, - 'uni21AB' : 8619, - 'uni01FB' : 507, - 'uni01FC' : 508, - 'uni223A' : 8762, - 'uni01FA' : 506, - 'uni01FF' : 511, - 'uni01FD' : 509, - 'uni01FE' : 510, - 'uni2567' : 9575, - 'uni25E0' : 9696, - 'uni0104' : 260, - 'uni0105' : 261, - 'uni0106' : 262, - 'uni0107' : 263, - 'uni0100' : 256, - 'uni0101' : 257, - 'uni0102' : 258, - 'uni0103' : 259, - 'uni2038' : 8248, - 'uni2009' : 8201, - 'uni2008' : 8200, - 'uni0108' : 264, - 'uni0109' : 265, - 'uni02A1' : 673, - 'uni223B' : 8763, - 'uni226C' : 8812, - 'uni25AC' : 9644, - 'uni24D3' : 9427, - 'uni21E0' : 8672, - 'uni21E3' : 8675, - 'Udieresis' : 220, - 'uni21E2' : 8674, - 'D' : 68, - 'uni21E5' : 8677, - 'uni2621' : 9761, - 'uni21D1' : 8657, - 'uni203E' : 8254, - 'uni22C6' : 8902, - 'uni21E4' : 8676, - 'uni010D' : 269, - 'uni010E' : 270, - 'uni010F' : 271, - 'five' : 53, - 'T' : 84, - 'uni010B' : 267, - 'uni010C' : 268, - 'uni2605' : 9733, - 'uni2663' : 9827, - 'uni21E6' : 8678, - 'uni24B6' : 9398, - 'uni22C1' : 8897, - 'oslash' : 248, - 'acute' : 180, - 'uni01F0' : 496, - 'd' : 100, - 'OE' : 338, - 'uni22E3' : 8931, - 'Igrave' : 204, - 'uni2308' : 8968, - 'uni2309' : 8969, - 'uni21A9' : 8617, - 't' : 116, - 'uni2313' : 8979, - 'uni03A3' : 931, - 'uni21A4' : 8612, - 'uni21A7' : 8615, - 'uni21A6' : 8614, - 'uni21A1' : 8609, - 'uni21A0' : 8608, - 'uni21A3' : 8611, - 'uni21A2' : 8610, - 'parenright' : 41, - 'uni256A' : 9578, - 'uni25DC' : 9692, - 'uni24CE' : 9422, - 'uni042C' : 1068, - 'uni24E0' : 9440, - 'uni042B' : 1067, - 'uni0409' : 1033, - 'uni0408' : 1032, - 'uni24E7' : 9447, - 'uni25B4' : 9652, - 'uni042A' : 1066, - 'uni228E' : 8846, - 'uni0401' : 1025, - 'adieresis' : 228, - 'uni0403' : 1027, - 'quotesingle' : 39, - 'uni0405' : 1029, - 'uni0404' : 1028, - 'uni0407' : 1031, - 'uni0406' : 1030, - 'uni229C' : 8860, - 'uni2306' : 8966, - 'uni2253' : 8787, - 'twodotenleader' : 8229, - 'uni2131' : 8497, - 'uni21DA' : 8666, - 'uni2234' : 8756, - 'uni2235' : 8757, - 'uni01A5' : 421, - 'uni2237' : 8759, - 'uni2230' : 8752, - 'uni02CC' : 716, - 'slash' : 47, - 'uni01A0' : 416, - 'ellipsis' : 8230, - 'uni2299' : 8857, - 'uni2238' : 8760, - 'numbersign' : 35, - 'uni21A8' : 8616, - 'uni223D' : 8765, - 'uni01AF' : 431, - 'uni223F' : 8767, - 'uni01AD' : 429, - 'uni01AB' : 427, - 'odieresis' : 246, - 'uni223C' : 8764, - 'uni227D' : 8829, - 'uni0280' : 640, - 'O' : 79, - 'uni227E' : 8830, - 'uni21A5' : 8613, - 'uni22D4' : 8916, - 'uni25D4' : 9684, - 'uni227F' : 8831, - 'uni0435' : 1077, - 'uni2302' : 8962, - 'uni2669' : 9833, - 'uni24E3' : 9443, - 'uni2720' : 10016, - 'uni22A8' : 8872, - 'uni22A9' : 8873, - 'uni040A' : 1034, - 'uni22A7' : 8871, - 'oe' : 339, - 'uni040B' : 1035, - 'uni040E' : 1038, - 'uni22A3' : 8867, - 'o' : 111, - 'uni040F' : 1039, - 'Edieresis' : 203, - 'uni25D5' : 9685, - 'plus' : 43, - 'uni044D' : 1101, - 'uni263C' : 9788, - 'uni22E6' : 8934, - 'uni2283' : 8835, - 'uni258C' : 9612, - 'uni219E' : 8606, - 'uni24E4' : 9444, - 'uni2136' : 8502, - 'dagger' : 8224, - 'uni24B7' : 9399, - 'uni219B' : 8603, - 'uni22E5' : 8933, - 'three' : 51, - 'uni210B' : 8459, - 'uni2534' : 9524, - 'uni24B8' : 9400, - 'uni230A' : 8970, - 'hungarumlaut' : 733, - 'parenleft' : 40, - 'uni0148' : 328, - 'uni0149' : 329, - 'uni2124' : 8484, - 'uni2125' : 8485, - 'uni2126' : 8486, - 'uni2127' : 8487, - 'uni0140' : 320, - 'uni2129' : 8489, - 'uni25C5' : 9669, - 'uni0143' : 323, - 'uni0144' : 324, - 'uni0145' : 325, - 'uni0146' : 326, - 'uni0147' : 327, - 'uni210D' : 8461, - 'fraction' : 8260, - 'uni2031' : 8241, - 'uni2196' : 8598, - 'uni2035' : 8245, - 'uni24E6' : 9446, - 'uni016B' : 363, - 'uni24BA' : 9402, - 'uni266A' : 9834, - 'uni0116' : 278, - 'uni2115' : 8469, - 'registered' : 174, - 'J' : 74, - 'uni25DF' : 9695, - 'uni25CE' : 9678, - 'uni273D' : 10045, - 'dieresis' : 168, - 'uni212B' : 8491, - 'uni0114' : 276, - 'uni212D' : 8493, - 'uni212E' : 8494, - 'uni212F' : 8495, - 'uni014A' : 330, - 'uni014B' : 331, - 'uni014C' : 332, - 'uni014D' : 333, - 'uni014E' : 334, - 'uni014F' : 335, - 'uni025E' : 606, - 'uni24E8' : 9448, - 'uni0111' : 273, - 'uni24E9' : 9449, - 'Ograve' : 210, - 'j' : 106, - 'uni2195' : 8597, - 'uni2194' : 8596, - 'uni2197' : 8599, - 'uni2037' : 8247, - 'uni2191' : 8593, - 'uni2190' : 8592, - 'uni2193' : 8595, - 'uni2192' : 8594, - 'uni29FA' : 10746, - 'uni2713' : 10003, - 'z' : 122, - 'uni2199' : 8601, - 'uni2198' : 8600, - 'uni2667' : 9831, - 'ae' : 230, - 'uni0448' : 1096, - 'semicolon' : 59, - 'uni2666' : 9830, - 'uni038F' : 911, - 'uni0444' : 1092, - 'uni0447' : 1095, - 'uni038E' : 910, - 'uni0441' : 1089, - 'uni038C' : 908, - 'uni0443' : 1091, - 'uni038A' : 906, - 'uni0250' : 592, - 'uni0251' : 593, - 'uni0252' : 594, - 'uni0253' : 595, - 'uni0254' : 596, - 'at' : 64, - 'uni0256' : 598, - 'uni0257' : 599, - 'uni0167' : 359, - 'uni0259' : 601, - 'uni228C' : 8844, - 'uni2662' : 9826, - 'uni0319' : 793, - 'uni0318' : 792, - 'uni24BC' : 9404, - 'uni0402' : 1026, - 'uni22EF' : 8943, - 'Iacute' : 205, - 'uni22ED' : 8941, - 'uni22EE' : 8942, - 'uni0311' : 785, - 'uni0310' : 784, - 'uni21E8' : 8680, - 'uni0312' : 786, - 'percent' : 37, - 'uni0317' : 791, - 'uni0316' : 790, - 'uni21D6' : 8662, - 'uni21D7' : 8663, - 'uni21D4' : 8660, - 'uni21D5' : 8661, - 'uni21D2' : 8658, - 'uni21D3' : 8659, - 'uni21D0' : 8656, - 'uni2138' : 8504, - 'uni2270' : 8816, - 'uni2271' : 8817, - 'uni2272' : 8818, - 'uni2273' : 8819, - 'uni2274' : 8820, - 'uni2275' : 8821, - 'bracketright' : 93, - 'uni21D9' : 8665, - 'uni21DF' : 8671, - 'uni21DD' : 8669, - 'uni21DE' : 8670, - 'AE' : 198, - 'uni03AE' : 942, - 'uni227A' : 8826, - 'uni227B' : 8827, - 'uni227C' : 8828, - 'asterisk' : 42, - 'aacute' : 225, - 'uni226F' : 8815, - 'uni22E2' : 8930, - 'uni0386' : 902, - 'uni22E0' : 8928, - 'uni22E1' : 8929, - 'U' : 85, - 'uni22E7' : 8935, - 'uni22E4' : 8932, - 'uni0387' : 903, - 'uni031A' : 794, - 'eacute' : 233, - 'uni22E8' : 8936, - 'uni22E9' : 8937, - 'uni24D8' : 9432, - 'uni025A' : 602, - 'uni025B' : 603, - 'uni025C' : 604, - 'e' : 101, - 'uni0128' : 296, - 'uni025F' : 607, - 'uni2665' : 9829, - 'thorn' : 254, - 'uni0129' : 297, - 'uni253C' : 9532, - 'uni25D7' : 9687, - 'u' : 117, - 'uni0388' : 904, - 'uni0389' : 905, - 'uni0255' : 597, - 'uni0171' : 369, - 'uni0384' : 900, - 'uni0385' : 901, - 'uni044A' : 1098, - 'uni252C' : 9516, - 'uni044C' : 1100, - 'uni044B' : 1099 -} - -uni2type1 = dict([(v,k) for k,v in type12uni.items()]) - tex2uni = { 'widehat' : 0x0302, 'widetilde' : 0x0303, @@ -2320,6 +973,20 @@ 'epsilon' : 949, 'vartheta' : 977, 'bigotimes' : 10754 + 'guillemotleft' : 171 + 'ring' : 730 + 'Thorn' : 222 + 'guilsinglright' : 8250 + 'perthousand' : 8240 + 'macron' : 175 + 'cent' : 162 + 'guillemotright' : 187 + 'equal' : 61 + 'asterisk' : 42 + 'guilsinglleft' : 8249 + 'plus' : 43 + 'thorn' : 254, + 'dagger' : 8224 } # Each element is a 4-tuple of the form: From 57eea58a742c6b734ba41d983e8b1b7cc336fdb6 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Sep 2011 13:21:03 -0400 Subject: [PATCH 124/214] Add missing commas. --- lib/matplotlib/_mathtext_data.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index a416c32eda95..8923b49dff90 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -972,19 +972,19 @@ 'biguplus' : 10756, 'epsilon' : 949, 'vartheta' : 977, - 'bigotimes' : 10754 - 'guillemotleft' : 171 - 'ring' : 730 - 'Thorn' : 222 - 'guilsinglright' : 8250 - 'perthousand' : 8240 - 'macron' : 175 - 'cent' : 162 - 'guillemotright' : 187 - 'equal' : 61 - 'asterisk' : 42 - 'guilsinglleft' : 8249 - 'plus' : 43 + 'bigotimes' : 10754, + 'guillemotleft' : 171, + 'ring' : 730, + 'Thorn' : 222, + 'guilsinglright' : 8250, + 'perthousand' : 8240, + 'macron' : 175, + 'cent' : 162, + 'guillemotright' : 187, + 'equal' : 61, + 'asterisk' : 42, + 'guilsinglleft' : 8249, + 'plus' : 43, 'thorn' : 254, 'dagger' : 8224 } From e65a1181c0bf4f36af587e5dbf76c6cc19b366b2 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Sep 2011 19:39:27 -0400 Subject: [PATCH 125/214] Fix afm.py --- lib/matplotlib/_mathtext_data.py | 1347 ++++++++++++++++++++++++++++++ 1 file changed, 1347 insertions(+) diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index 8923b49dff90..fd1ece2b7da7 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -413,6 +413,1353 @@ r'\combiningdotabove' : ('pncri8a', 26), # for \dot } +# Automatically generated. + +type12uni = { + 'uni24C8' : 9416, + 'aring' : 229, + 'uni22A0' : 8864, + 'uni2292' : 8850, + 'quotedblright' : 8221, + 'uni03D2' : 978, + 'uni2215' : 8725, + 'uni03D0' : 976, + 'V' : 86, + 'dollar' : 36, + 'uni301E' : 12318, + 'uni03D5' : 981, + 'four' : 52, + 'uni25A0' : 9632, + 'uni013C' : 316, + 'uni013B' : 315, + 'uni013E' : 318, + 'Yacute' : 221, + 'uni25DE' : 9694, + 'uni013F' : 319, + 'uni255A' : 9562, + 'uni2606' : 9734, + 'uni0180' : 384, + 'uni22B7' : 8887, + 'uni044F' : 1103, + 'uni22B5' : 8885, + 'uni22B4' : 8884, + 'uni22AE' : 8878, + 'uni22B2' : 8882, + 'uni22B1' : 8881, + 'uni22B0' : 8880, + 'uni25CD' : 9677, + 'uni03CE' : 974, + 'uni03CD' : 973, + 'uni03CC' : 972, + 'uni03CB' : 971, + 'uni03CA' : 970, + 'uni22B8' : 8888, + 'uni22C9' : 8905, + 'uni0449' : 1097, + 'uni20DD' : 8413, + 'uni20DC' : 8412, + 'uni20DB' : 8411, + 'uni2231' : 8753, + 'uni25CF' : 9679, + 'uni306E' : 12398, + 'uni03D1' : 977, + 'uni01A1' : 417, + 'uni20D7' : 8407, + 'uni03D6' : 982, + 'uni2233' : 8755, + 'uni20D2' : 8402, + 'uni20D1' : 8401, + 'uni20D0' : 8400, + 'P' : 80, + 'uni22BE' : 8894, + 'uni22BD' : 8893, + 'uni22BC' : 8892, + 'uni22BB' : 8891, + 'underscore' : 95, + 'uni03C8' : 968, + 'uni03C7' : 967, + 'uni0328' : 808, + 'uni03C5' : 965, + 'uni03C4' : 964, + 'uni03C3' : 963, + 'uni03C2' : 962, + 'uni03C1' : 961, + 'uni03C0' : 960, + 'uni2010' : 8208, + 'uni0130' : 304, + 'uni0133' : 307, + 'uni0132' : 306, + 'uni0135' : 309, + 'uni0134' : 308, + 'uni0137' : 311, + 'uni0136' : 310, + 'uni0139' : 313, + 'uni0138' : 312, + 'uni2244' : 8772, + 'uni229A' : 8858, + 'uni2571' : 9585, + 'uni0278' : 632, + 'uni2239' : 8761, + 'p' : 112, + 'uni3019' : 12313, + 'uni25CB' : 9675, + 'uni03DB' : 987, + 'uni03DC' : 988, + 'uni03DA' : 986, + 'uni03DF' : 991, + 'uni03DD' : 989, + 'uni013D' : 317, + 'uni220A' : 8714, + 'uni220C' : 8716, + 'uni220B' : 8715, + 'uni220E' : 8718, + 'uni220D' : 8717, + 'uni220F' : 8719, + 'uni22CC' : 8908, + 'Otilde' : 213, + 'uni25E5' : 9701, + 'uni2736' : 10038, + 'perthousand' : 8240, + 'zero' : 48, + 'uni279B' : 10139, + 'dotlessi' : 305, + 'uni2279' : 8825, + 'Scaron' : 352, + 'zcaron' : 382, + 'uni21D8' : 8664, + 'egrave' : 232, + 'uni0271' : 625, + 'uni01AA' : 426, + 'uni2332' : 9010, + 'section' : 167, + 'uni25E4' : 9700, + 'Icircumflex' : 206, + 'ntilde' : 241, + 'uni041E' : 1054, + 'ampersand' : 38, + 'uni041C' : 1052, + 'uni041A' : 1050, + 'uni22AB' : 8875, + 'uni21DB' : 8667, + 'dotaccent' : 729, + 'uni0416' : 1046, + 'uni0417' : 1047, + 'uni0414' : 1044, + 'uni0415' : 1045, + 'uni0412' : 1042, + 'uni0413' : 1043, + 'degree' : 176, + 'uni0411' : 1041, + 'K' : 75, + 'uni25EB' : 9707, + 'uni25EF' : 9711, + 'uni0418' : 1048, + 'uni0419' : 1049, + 'uni2263' : 8803, + 'uni226E' : 8814, + 'uni2251' : 8785, + 'uni02C8' : 712, + 'uni2262' : 8802, + 'acircumflex' : 226, + 'uni22B3' : 8883, + 'uni2261' : 8801, + 'uni2394' : 9108, + 'Aring' : 197, + 'uni2260' : 8800, + 'uni2254' : 8788, + 'uni0436' : 1078, + 'uni2267' : 8807, + 'k' : 107, + 'uni22C8' : 8904, + 'uni226A' : 8810, + 'uni231F' : 8991, + 'smalltilde' : 732, + 'uni2201' : 8705, + 'uni2200' : 8704, + 'uni2203' : 8707, + 'uni02BD' : 701, + 'uni2205' : 8709, + 'uni2204' : 8708, + 'Agrave' : 192, + 'uni2206' : 8710, + 'uni2209' : 8713, + 'uni2208' : 8712, + 'uni226D' : 8813, + 'uni2264' : 8804, + 'uni263D' : 9789, + 'uni2258' : 8792, + 'uni02D3' : 723, + 'uni02D2' : 722, + 'uni02D1' : 721, + 'uni02D0' : 720, + 'uni25E1' : 9697, + 'divide' : 247, + 'uni02D5' : 725, + 'uni02D4' : 724, + 'ocircumflex' : 244, + 'uni2524' : 9508, + 'uni043A' : 1082, + 'uni24CC' : 9420, + 'asciitilde' : 126, + 'uni22B9' : 8889, + 'uni24D2' : 9426, + 'uni211E' : 8478, + 'uni211D' : 8477, + 'uni24DD' : 9437, + 'uni211A' : 8474, + 'uni211C' : 8476, + 'uni211B' : 8475, + 'uni25C6' : 9670, + 'uni017F' : 383, + 'uni017A' : 378, + 'uni017C' : 380, + 'uni017B' : 379, + 'uni0346' : 838, + 'uni22F1' : 8945, + 'uni22F0' : 8944, + 'two' : 50, + 'uni2298' : 8856, + 'uni24D1' : 9425, + 'E' : 69, + 'uni025D' : 605, + 'scaron' : 353, + 'uni2322' : 8994, + 'uni25E3' : 9699, + 'uni22BF' : 8895, + 'F' : 70, + 'uni0440' : 1088, + 'uni255E' : 9566, + 'uni22BA' : 8890, + 'uni0175' : 373, + 'uni0174' : 372, + 'uni0177' : 375, + 'uni0176' : 374, + 'bracketleft' : 91, + 'uni0170' : 368, + 'uni0173' : 371, + 'uni0172' : 370, + 'asciicircum' : 94, + 'uni0179' : 377, + 'uni2590' : 9616, + 'uni25E2' : 9698, + 'uni2119' : 8473, + 'uni2118' : 8472, + 'uni25CC' : 9676, + 'f' : 102, + 'ordmasculine' : 186, + 'uni229B' : 8859, + 'uni22A1' : 8865, + 'uni2111' : 8465, + 'uni2110' : 8464, + 'uni2113' : 8467, + 'uni2112' : 8466, + 'mu' : 181, + 'uni2281' : 8833, + 'paragraph' : 182, + 'nine' : 57, + 'uni25EC' : 9708, + 'v' : 118, + 'uni040C' : 1036, + 'uni0113' : 275, + 'uni22D0' : 8912, + 'uni21CC' : 8652, + 'uni21CB' : 8651, + 'uni21CA' : 8650, + 'uni22A5' : 8869, + 'uni21CF' : 8655, + 'uni21CE' : 8654, + 'uni21CD' : 8653, + 'guilsinglleft' : 8249, + 'backslash' : 92, + 'uni2284' : 8836, + 'uni224E' : 8782, + 'uni224D' : 8781, + 'uni224F' : 8783, + 'uni224A' : 8778, + 'uni2287' : 8839, + 'uni224C' : 8780, + 'uni224B' : 8779, + 'uni21BD' : 8637, + 'uni2286' : 8838, + 'uni030F' : 783, + 'uni030D' : 781, + 'uni030E' : 782, + 'uni030B' : 779, + 'uni030C' : 780, + 'uni030A' : 778, + 'uni026E' : 622, + 'uni026D' : 621, + 'six' : 54, + 'uni026A' : 618, + 'uni026C' : 620, + 'uni25C1' : 9665, + 'uni20D6' : 8406, + 'uni045B' : 1115, + 'uni045C' : 1116, + 'uni256B' : 9579, + 'uni045A' : 1114, + 'uni045F' : 1119, + 'uni045E' : 1118, + 'A' : 65, + 'uni2569' : 9577, + 'uni0458' : 1112, + 'uni0459' : 1113, + 'uni0452' : 1106, + 'uni0453' : 1107, + 'uni2562' : 9570, + 'uni0451' : 1105, + 'uni0456' : 1110, + 'uni0457' : 1111, + 'uni0454' : 1108, + 'uni0455' : 1109, + 'icircumflex' : 238, + 'uni0307' : 775, + 'uni0304' : 772, + 'uni0305' : 773, + 'uni0269' : 617, + 'uni0268' : 616, + 'uni0300' : 768, + 'uni0301' : 769, + 'uni0265' : 613, + 'uni0264' : 612, + 'uni0267' : 615, + 'uni0266' : 614, + 'uni0261' : 609, + 'uni0260' : 608, + 'uni0263' : 611, + 'uni0262' : 610, + 'a' : 97, + 'uni2207' : 8711, + 'uni2247' : 8775, + 'uni2246' : 8774, + 'uni2241' : 8769, + 'uni2240' : 8768, + 'uni2243' : 8771, + 'uni2242' : 8770, + 'uni2312' : 8978, + 'ogonek' : 731, + 'uni2249' : 8777, + 'uni2248' : 8776, + 'uni3030' : 12336, + 'q' : 113, + 'uni21C2' : 8642, + 'uni21C1' : 8641, + 'uni21C0' : 8640, + 'uni21C7' : 8647, + 'uni21C6' : 8646, + 'uni21C5' : 8645, + 'uni21C4' : 8644, + 'uni225F' : 8799, + 'uni212C' : 8492, + 'uni21C8' : 8648, + 'uni2467' : 9319, + 'oacute' : 243, + 'uni028F' : 655, + 'uni028E' : 654, + 'uni026F' : 623, + 'uni028C' : 652, + 'uni028B' : 651, + 'uni028A' : 650, + 'uni2510' : 9488, + 'ograve' : 242, + 'edieresis' : 235, + 'uni22CE' : 8910, + 'uni22CF' : 8911, + 'uni219F' : 8607, + 'comma' : 44, + 'uni22CA' : 8906, + 'uni0429' : 1065, + 'uni03C6' : 966, + 'uni0427' : 1063, + 'uni0426' : 1062, + 'uni0425' : 1061, + 'uni0424' : 1060, + 'uni0423' : 1059, + 'uni0422' : 1058, + 'uni0421' : 1057, + 'uni0420' : 1056, + 'uni2465' : 9317, + 'uni24D0' : 9424, + 'uni2464' : 9316, + 'uni0430' : 1072, + 'otilde' : 245, + 'uni2661' : 9825, + 'uni24D6' : 9430, + 'uni2466' : 9318, + 'uni24D5' : 9429, + 'uni219A' : 8602, + 'uni2518' : 9496, + 'uni22B6' : 8886, + 'uni2461' : 9313, + 'uni24D4' : 9428, + 'uni2460' : 9312, + 'uni24EA' : 9450, + 'guillemotright' : 187, + 'ecircumflex' : 234, + 'greater' : 62, + 'uni2011' : 8209, + 'uacute' : 250, + 'uni2462' : 9314, + 'L' : 76, + 'bullet' : 8226, + 'uni02A4' : 676, + 'uni02A7' : 679, + 'cedilla' : 184, + 'uni02A2' : 674, + 'uni2015' : 8213, + 'uni22C4' : 8900, + 'uni22C5' : 8901, + 'uni22AD' : 8877, + 'uni22C7' : 8903, + 'uni22C0' : 8896, + 'uni2016' : 8214, + 'uni22C2' : 8898, + 'uni22C3' : 8899, + 'uni24CF' : 9423, + 'uni042F' : 1071, + 'uni042E' : 1070, + 'uni042D' : 1069, + 'ydieresis' : 255, + 'l' : 108, + 'logicalnot' : 172, + 'uni24CA' : 9418, + 'uni0287' : 647, + 'uni0286' : 646, + 'uni0285' : 645, + 'uni0284' : 644, + 'uni0283' : 643, + 'uni0282' : 642, + 'uni0281' : 641, + 'uni027C' : 636, + 'uni2664' : 9828, + 'exclamdown' : 161, + 'uni25C4' : 9668, + 'uni0289' : 649, + 'uni0288' : 648, + 'uni039A' : 922, + 'endash' : 8211, + 'uni2640' : 9792, + 'uni20E4' : 8420, + 'uni0473' : 1139, + 'uni20E1' : 8417, + 'uni2642' : 9794, + 'uni03B8' : 952, + 'uni03B9' : 953, + 'agrave' : 224, + 'uni03B4' : 948, + 'uni03B5' : 949, + 'uni03B6' : 950, + 'uni03B7' : 951, + 'uni03B0' : 944, + 'uni03B1' : 945, + 'uni03B2' : 946, + 'uni03B3' : 947, + 'uni2555' : 9557, + 'Adieresis' : 196, + 'germandbls' : 223, + 'Odieresis' : 214, + 'space' : 32, + 'uni0126' : 294, + 'uni0127' : 295, + 'uni0124' : 292, + 'uni0125' : 293, + 'uni0122' : 290, + 'uni0123' : 291, + 'uni0120' : 288, + 'uni0121' : 289, + 'quoteright' : 8217, + 'uni2560' : 9568, + 'uni2556' : 9558, + 'ucircumflex' : 251, + 'uni2561' : 9569, + 'uni2551' : 9553, + 'uni25B2' : 9650, + 'uni2550' : 9552, + 'uni2563' : 9571, + 'uni2553' : 9555, + 'G' : 71, + 'uni2564' : 9572, + 'uni2552' : 9554, + 'quoteleft' : 8216, + 'uni2565' : 9573, + 'uni2572' : 9586, + 'uni2568' : 9576, + 'uni2566' : 9574, + 'W' : 87, + 'uni214A' : 8522, + 'uni012F' : 303, + 'uni012D' : 301, + 'uni012E' : 302, + 'uni012B' : 299, + 'uni012C' : 300, + 'uni255C' : 9564, + 'uni012A' : 298, + 'uni2289' : 8841, + 'Q' : 81, + 'uni2320' : 8992, + 'uni2321' : 8993, + 'g' : 103, + 'uni03BD' : 957, + 'uni03BE' : 958, + 'uni03BF' : 959, + 'uni2282' : 8834, + 'uni2285' : 8837, + 'uni03BA' : 954, + 'uni03BB' : 955, + 'uni03BC' : 956, + 'uni2128' : 8488, + 'uni25B7' : 9655, + 'w' : 119, + 'uni0302' : 770, + 'uni03DE' : 990, + 'uni25DA' : 9690, + 'uni0303' : 771, + 'uni0463' : 1123, + 'uni0462' : 1122, + 'uni3018' : 12312, + 'uni2514' : 9492, + 'question' : 63, + 'uni25B3' : 9651, + 'uni24E1' : 9441, + 'one' : 49, + 'uni200A' : 8202, + 'uni2278' : 8824, + 'ring' : 730, + 'uni0195' : 405, + 'figuredash' : 8210, + 'uni22EC' : 8940, + 'uni0339' : 825, + 'uni0338' : 824, + 'uni0337' : 823, + 'uni0336' : 822, + 'uni0335' : 821, + 'uni0333' : 819, + 'uni0332' : 818, + 'uni0331' : 817, + 'uni0330' : 816, + 'uni01C1' : 449, + 'uni01C0' : 448, + 'uni01C3' : 451, + 'uni01C2' : 450, + 'uni2353' : 9043, + 'uni0308' : 776, + 'uni2218' : 8728, + 'uni2219' : 8729, + 'uni2216' : 8726, + 'uni2217' : 8727, + 'uni2214' : 8724, + 'uni0309' : 777, + 'uni2609' : 9737, + 'uni2213' : 8723, + 'uni2210' : 8720, + 'uni2211' : 8721, + 'uni2245' : 8773, + 'B' : 66, + 'uni25D6' : 9686, + 'iacute' : 237, + 'uni02E6' : 742, + 'uni02E7' : 743, + 'uni02E8' : 744, + 'uni02E9' : 745, + 'uni221D' : 8733, + 'uni221E' : 8734, + 'Ydieresis' : 376, + 'uni221C' : 8732, + 'uni22D7' : 8919, + 'uni221A' : 8730, + 'R' : 82, + 'uni24DC' : 9436, + 'uni033F' : 831, + 'uni033E' : 830, + 'uni033C' : 828, + 'uni033B' : 827, + 'uni033A' : 826, + 'b' : 98, + 'uni228A' : 8842, + 'uni22DB' : 8923, + 'uni2554' : 9556, + 'uni046B' : 1131, + 'uni046A' : 1130, + 'r' : 114, + 'uni24DB' : 9435, + 'Ccedilla' : 199, + 'minus' : 8722, + 'uni24DA' : 9434, + 'uni03F0' : 1008, + 'uni03F1' : 1009, + 'uni20AC' : 8364, + 'uni2276' : 8822, + 'uni24C0' : 9408, + 'uni0162' : 354, + 'uni0163' : 355, + 'uni011E' : 286, + 'uni011D' : 285, + 'uni011C' : 284, + 'uni011B' : 283, + 'uni0164' : 356, + 'uni0165' : 357, + 'Lslash' : 321, + 'uni0168' : 360, + 'uni0169' : 361, + 'uni25C9' : 9673, + 'uni02E5' : 741, + 'uni21C3' : 8643, + 'uni24C4' : 9412, + 'uni24E2' : 9442, + 'uni2277' : 8823, + 'uni013A' : 314, + 'uni2102' : 8450, + 'Uacute' : 218, + 'uni2317' : 8983, + 'uni2107' : 8455, + 'uni221F' : 8735, + 'yacute' : 253, + 'uni3012' : 12306, + 'Ucircumflex' : 219, + 'uni015D' : 349, + 'quotedbl' : 34, + 'uni25D9' : 9689, + 'uni2280' : 8832, + 'uni22AF' : 8879, + 'onehalf' : 189, + 'uni221B' : 8731, + 'Thorn' : 222, + 'uni2226' : 8742, + 'M' : 77, + 'uni25BA' : 9658, + 'uni2463' : 9315, + 'uni2336' : 9014, + 'eight' : 56, + 'uni2236' : 8758, + 'multiply' : 215, + 'uni210C' : 8460, + 'uni210A' : 8458, + 'uni21C9' : 8649, + 'grave' : 96, + 'uni210E' : 8462, + 'uni0117' : 279, + 'uni016C' : 364, + 'uni0115' : 277, + 'uni016A' : 362, + 'uni016F' : 367, + 'uni0112' : 274, + 'uni016D' : 365, + 'uni016E' : 366, + 'Ocircumflex' : 212, + 'uni2305' : 8965, + 'm' : 109, + 'uni24DF' : 9439, + 'uni0119' : 281, + 'uni0118' : 280, + 'uni20A3' : 8355, + 'uni20A4' : 8356, + 'uni20A7' : 8359, + 'uni2288' : 8840, + 'uni24C3' : 9411, + 'uni251C' : 9500, + 'uni228D' : 8845, + 'uni222F' : 8751, + 'uni222E' : 8750, + 'uni222D' : 8749, + 'uni222C' : 8748, + 'uni222B' : 8747, + 'uni222A' : 8746, + 'uni255B' : 9563, + 'Ugrave' : 217, + 'uni24DE' : 9438, + 'guilsinglright' : 8250, + 'uni250A' : 9482, + 'Ntilde' : 209, + 'uni0279' : 633, + 'questiondown' : 191, + 'uni256C' : 9580, + 'Atilde' : 195, + 'uni0272' : 626, + 'uni0273' : 627, + 'uni0270' : 624, + 'ccedilla' : 231, + 'uni0276' : 630, + 'uni0277' : 631, + 'uni0274' : 628, + 'uni0275' : 629, + 'uni2252' : 8786, + 'uni041F' : 1055, + 'uni2250' : 8784, + 'Z' : 90, + 'uni2256' : 8790, + 'uni2257' : 8791, + 'copyright' : 169, + 'uni2255' : 8789, + 'uni043D' : 1085, + 'uni043E' : 1086, + 'uni043F' : 1087, + 'yen' : 165, + 'uni041D' : 1053, + 'uni043B' : 1083, + 'uni043C' : 1084, + 'uni21B0' : 8624, + 'uni21B1' : 8625, + 'uni21B2' : 8626, + 'uni21B3' : 8627, + 'uni21B4' : 8628, + 'uni21B5' : 8629, + 'uni21B6' : 8630, + 'uni21B7' : 8631, + 'uni21B8' : 8632, + 'Eacute' : 201, + 'uni2311' : 8977, + 'uni2310' : 8976, + 'uni228F' : 8847, + 'uni25DB' : 9691, + 'uni21BA' : 8634, + 'uni21BB' : 8635, + 'uni21BC' : 8636, + 'uni2017' : 8215, + 'uni21BE' : 8638, + 'uni21BF' : 8639, + 'uni231C' : 8988, + 'H' : 72, + 'uni0293' : 659, + 'uni2202' : 8706, + 'uni22A4' : 8868, + 'uni231E' : 8990, + 'uni2232' : 8754, + 'uni225B' : 8795, + 'uni225C' : 8796, + 'uni24D9' : 9433, + 'uni225A' : 8794, + 'uni0438' : 1080, + 'uni0439' : 1081, + 'uni225D' : 8797, + 'uni225E' : 8798, + 'uni0434' : 1076, + 'X' : 88, + 'uni007F' : 127, + 'uni0437' : 1079, + 'Idieresis' : 207, + 'uni0431' : 1073, + 'uni0432' : 1074, + 'uni0433' : 1075, + 'uni22AC' : 8876, + 'uni22CD' : 8909, + 'uni25A3' : 9635, + 'bar' : 124, + 'uni24BB' : 9403, + 'uni037E' : 894, + 'uni027B' : 635, + 'h' : 104, + 'uni027A' : 634, + 'uni027F' : 639, + 'uni027D' : 637, + 'uni027E' : 638, + 'uni2227' : 8743, + 'uni2004' : 8196, + 'uni2225' : 8741, + 'uni2224' : 8740, + 'uni2223' : 8739, + 'uni2222' : 8738, + 'uni2221' : 8737, + 'uni2220' : 8736, + 'x' : 120, + 'uni2323' : 8995, + 'uni2559' : 9561, + 'uni2558' : 9560, + 'uni2229' : 8745, + 'uni2228' : 8744, + 'udieresis' : 252, + 'uni029D' : 669, + 'ordfeminine' : 170, + 'uni22CB' : 8907, + 'uni233D' : 9021, + 'uni0428' : 1064, + 'uni24C6' : 9414, + 'uni22DD' : 8925, + 'uni24C7' : 9415, + 'uni015C' : 348, + 'uni015B' : 347, + 'uni015A' : 346, + 'uni22AA' : 8874, + 'uni015F' : 351, + 'uni015E' : 350, + 'braceleft' : 123, + 'uni24C5' : 9413, + 'uni0410' : 1040, + 'uni03AA' : 938, + 'uni24C2' : 9410, + 'uni03AC' : 940, + 'uni03AB' : 939, + 'macron' : 175, + 'uni03AD' : 941, + 'uni03AF' : 943, + 'uni0294' : 660, + 'uni0295' : 661, + 'uni0296' : 662, + 'uni0297' : 663, + 'uni0290' : 656, + 'uni0291' : 657, + 'uni0292' : 658, + 'atilde' : 227, + 'Acircumflex' : 194, + 'uni2370' : 9072, + 'uni24C1' : 9409, + 'uni0298' : 664, + 'uni0299' : 665, + 'Oslash' : 216, + 'uni029E' : 670, + 'C' : 67, + 'quotedblleft' : 8220, + 'uni029B' : 667, + 'uni029C' : 668, + 'uni03A9' : 937, + 'uni03A8' : 936, + 'S' : 83, + 'uni24C9' : 9417, + 'uni03A1' : 929, + 'uni03A0' : 928, + 'exclam' : 33, + 'uni03A5' : 933, + 'uni03A4' : 932, + 'uni03A7' : 935, + 'Zcaron' : 381, + 'uni2133' : 8499, + 'uni2132' : 8498, + 'uni0159' : 345, + 'uni0158' : 344, + 'uni2137' : 8503, + 'uni2005' : 8197, + 'uni2135' : 8501, + 'uni2134' : 8500, + 'uni02BA' : 698, + 'uni2033' : 8243, + 'uni0151' : 337, + 'uni0150' : 336, + 'uni0157' : 343, + 'equal' : 61, + 'uni0155' : 341, + 'uni0154' : 340, + 's' : 115, + 'uni233F' : 9023, + 'eth' : 240, + 'uni24BE' : 9406, + 'uni21E9' : 8681, + 'uni2060' : 8288, + 'Egrave' : 200, + 'uni255D' : 9565, + 'uni24CD' : 9421, + 'uni21E1' : 8673, + 'uni21B9' : 8633, + 'hyphen' : 45, + 'uni01BE' : 446, + 'uni01BB' : 443, + 'period' : 46, + 'igrave' : 236, + 'uni01BA' : 442, + 'uni2296' : 8854, + 'uni2297' : 8855, + 'uni2294' : 8852, + 'uni2295' : 8853, + 'colon' : 58, + 'uni2293' : 8851, + 'uni2290' : 8848, + 'uni2291' : 8849, + 'uni032D' : 813, + 'uni032E' : 814, + 'uni032F' : 815, + 'uni032A' : 810, + 'uni032B' : 811, + 'uni032C' : 812, + 'uni231D' : 8989, + 'Ecircumflex' : 202, + 'uni24D7' : 9431, + 'uni25DD' : 9693, + 'trademark' : 8482, + 'Aacute' : 193, + 'cent' : 162, + 'uni0445' : 1093, + 'uni266E' : 9838, + 'uni266D' : 9837, + 'uni266B' : 9835, + 'uni03C9' : 969, + 'uni2003' : 8195, + 'uni2047' : 8263, + 'lslash' : 322, + 'uni03A6' : 934, + 'uni2043' : 8259, + 'uni250C' : 9484, + 'uni2040' : 8256, + 'uni255F' : 9567, + 'uni24CB' : 9419, + 'uni0472' : 1138, + 'uni0446' : 1094, + 'uni0474' : 1140, + 'uni0475' : 1141, + 'uni2508' : 9480, + 'uni2660' : 9824, + 'uni2506' : 9478, + 'uni2502' : 9474, + 'c' : 99, + 'uni2500' : 9472, + 'N' : 78, + 'uni22A6' : 8870, + 'uni21E7' : 8679, + 'uni2130' : 8496, + 'uni2002' : 8194, + 'breve' : 728, + 'uni0442' : 1090, + 'Oacute' : 211, + 'uni229F' : 8863, + 'uni25C7' : 9671, + 'uni229D' : 8861, + 'uni229E' : 8862, + 'guillemotleft' : 171, + 'uni0329' : 809, + 'uni24E5' : 9445, + 'uni011F' : 287, + 'uni0324' : 804, + 'uni0325' : 805, + 'uni0326' : 806, + 'uni0327' : 807, + 'uni0321' : 801, + 'uni0322' : 802, + 'n' : 110, + 'uni2032' : 8242, + 'uni2269' : 8809, + 'uni2268' : 8808, + 'uni0306' : 774, + 'uni226B' : 8811, + 'uni21EA' : 8682, + 'uni0166' : 358, + 'uni203B' : 8251, + 'uni01B5' : 437, + 'idieresis' : 239, + 'uni02BC' : 700, + 'uni01B0' : 432, + 'braceright' : 125, + 'seven' : 55, + 'uni02BB' : 699, + 'uni011A' : 282, + 'uni29FB' : 10747, + 'brokenbar' : 166, + 'uni2036' : 8246, + 'uni25C0' : 9664, + 'uni0156' : 342, + 'uni22D5' : 8917, + 'uni0258' : 600, + 'ugrave' : 249, + 'uni22D6' : 8918, + 'uni22D1' : 8913, + 'uni2034' : 8244, + 'uni22D3' : 8915, + 'uni22D2' : 8914, + 'uni203C' : 8252, + 'uni223E' : 8766, + 'uni02BF' : 703, + 'uni22D9' : 8921, + 'uni22D8' : 8920, + 'uni25BD' : 9661, + 'uni25BE' : 9662, + 'uni25BF' : 9663, + 'uni041B' : 1051, + 'periodcentered' : 183, + 'uni25BC' : 9660, + 'uni019E' : 414, + 'uni019B' : 411, + 'uni019A' : 410, + 'uni2007' : 8199, + 'uni0391' : 913, + 'uni0390' : 912, + 'uni0393' : 915, + 'uni0392' : 914, + 'uni0395' : 917, + 'uni0394' : 916, + 'uni0397' : 919, + 'uni0396' : 918, + 'uni0399' : 921, + 'uni0398' : 920, + 'uni25C8' : 9672, + 'uni2468' : 9320, + 'sterling' : 163, + 'uni22EB' : 8939, + 'uni039C' : 924, + 'uni039B' : 923, + 'uni039E' : 926, + 'uni039D' : 925, + 'uni039F' : 927, + 'I' : 73, + 'uni03E1' : 993, + 'uni03E0' : 992, + 'uni2319' : 8985, + 'uni228B' : 8843, + 'uni25B5' : 9653, + 'uni25B6' : 9654, + 'uni22EA' : 8938, + 'uni24B9' : 9401, + 'uni044E' : 1102, + 'uni0199' : 409, + 'uni2266' : 8806, + 'Y' : 89, + 'uni22A2' : 8866, + 'Eth' : 208, + 'uni266F' : 9839, + 'emdash' : 8212, + 'uni263B' : 9787, + 'uni24BD' : 9405, + 'uni22DE' : 8926, + 'uni0360' : 864, + 'uni2557' : 9559, + 'uni22DF' : 8927, + 'uni22DA' : 8922, + 'uni22DC' : 8924, + 'uni0361' : 865, + 'i' : 105, + 'uni24BF' : 9407, + 'uni0362' : 866, + 'uni263E' : 9790, + 'uni028D' : 653, + 'uni2259' : 8793, + 'uni0323' : 803, + 'uni2265' : 8805, + 'daggerdbl' : 8225, + 'y' : 121, + 'uni010A' : 266, + 'plusminus' : 177, + 'less' : 60, + 'uni21AE' : 8622, + 'uni0315' : 789, + 'uni230B' : 8971, + 'uni21AF' : 8623, + 'uni21AA' : 8618, + 'uni21AC' : 8620, + 'uni21AB' : 8619, + 'uni01FB' : 507, + 'uni01FC' : 508, + 'uni223A' : 8762, + 'uni01FA' : 506, + 'uni01FF' : 511, + 'uni01FD' : 509, + 'uni01FE' : 510, + 'uni2567' : 9575, + 'uni25E0' : 9696, + 'uni0104' : 260, + 'uni0105' : 261, + 'uni0106' : 262, + 'uni0107' : 263, + 'uni0100' : 256, + 'uni0101' : 257, + 'uni0102' : 258, + 'uni0103' : 259, + 'uni2038' : 8248, + 'uni2009' : 8201, + 'uni2008' : 8200, + 'uni0108' : 264, + 'uni0109' : 265, + 'uni02A1' : 673, + 'uni223B' : 8763, + 'uni226C' : 8812, + 'uni25AC' : 9644, + 'uni24D3' : 9427, + 'uni21E0' : 8672, + 'uni21E3' : 8675, + 'Udieresis' : 220, + 'uni21E2' : 8674, + 'D' : 68, + 'uni21E5' : 8677, + 'uni2621' : 9761, + 'uni21D1' : 8657, + 'uni203E' : 8254, + 'uni22C6' : 8902, + 'uni21E4' : 8676, + 'uni010D' : 269, + 'uni010E' : 270, + 'uni010F' : 271, + 'five' : 53, + 'T' : 84, + 'uni010B' : 267, + 'uni010C' : 268, + 'uni2605' : 9733, + 'uni2663' : 9827, + 'uni21E6' : 8678, + 'uni24B6' : 9398, + 'uni22C1' : 8897, + 'oslash' : 248, + 'acute' : 180, + 'uni01F0' : 496, + 'd' : 100, + 'OE' : 338, + 'uni22E3' : 8931, + 'Igrave' : 204, + 'uni2308' : 8968, + 'uni2309' : 8969, + 'uni21A9' : 8617, + 't' : 116, + 'uni2313' : 8979, + 'uni03A3' : 931, + 'uni21A4' : 8612, + 'uni21A7' : 8615, + 'uni21A6' : 8614, + 'uni21A1' : 8609, + 'uni21A0' : 8608, + 'uni21A3' : 8611, + 'uni21A2' : 8610, + 'parenright' : 41, + 'uni256A' : 9578, + 'uni25DC' : 9692, + 'uni24CE' : 9422, + 'uni042C' : 1068, + 'uni24E0' : 9440, + 'uni042B' : 1067, + 'uni0409' : 1033, + 'uni0408' : 1032, + 'uni24E7' : 9447, + 'uni25B4' : 9652, + 'uni042A' : 1066, + 'uni228E' : 8846, + 'uni0401' : 1025, + 'adieresis' : 228, + 'uni0403' : 1027, + 'quotesingle' : 39, + 'uni0405' : 1029, + 'uni0404' : 1028, + 'uni0407' : 1031, + 'uni0406' : 1030, + 'uni229C' : 8860, + 'uni2306' : 8966, + 'uni2253' : 8787, + 'twodotenleader' : 8229, + 'uni2131' : 8497, + 'uni21DA' : 8666, + 'uni2234' : 8756, + 'uni2235' : 8757, + 'uni01A5' : 421, + 'uni2237' : 8759, + 'uni2230' : 8752, + 'uni02CC' : 716, + 'slash' : 47, + 'uni01A0' : 416, + 'ellipsis' : 8230, + 'uni2299' : 8857, + 'uni2238' : 8760, + 'numbersign' : 35, + 'uni21A8' : 8616, + 'uni223D' : 8765, + 'uni01AF' : 431, + 'uni223F' : 8767, + 'uni01AD' : 429, + 'uni01AB' : 427, + 'odieresis' : 246, + 'uni223C' : 8764, + 'uni227D' : 8829, + 'uni0280' : 640, + 'O' : 79, + 'uni227E' : 8830, + 'uni21A5' : 8613, + 'uni22D4' : 8916, + 'uni25D4' : 9684, + 'uni227F' : 8831, + 'uni0435' : 1077, + 'uni2302' : 8962, + 'uni2669' : 9833, + 'uni24E3' : 9443, + 'uni2720' : 10016, + 'uni22A8' : 8872, + 'uni22A9' : 8873, + 'uni040A' : 1034, + 'uni22A7' : 8871, + 'oe' : 339, + 'uni040B' : 1035, + 'uni040E' : 1038, + 'uni22A3' : 8867, + 'o' : 111, + 'uni040F' : 1039, + 'Edieresis' : 203, + 'uni25D5' : 9685, + 'plus' : 43, + 'uni044D' : 1101, + 'uni263C' : 9788, + 'uni22E6' : 8934, + 'uni2283' : 8835, + 'uni258C' : 9612, + 'uni219E' : 8606, + 'uni24E4' : 9444, + 'uni2136' : 8502, + 'dagger' : 8224, + 'uni24B7' : 9399, + 'uni219B' : 8603, + 'uni22E5' : 8933, + 'three' : 51, + 'uni210B' : 8459, + 'uni2534' : 9524, + 'uni24B8' : 9400, + 'uni230A' : 8970, + 'hungarumlaut' : 733, + 'parenleft' : 40, + 'uni0148' : 328, + 'uni0149' : 329, + 'uni2124' : 8484, + 'uni2125' : 8485, + 'uni2126' : 8486, + 'uni2127' : 8487, + 'uni0140' : 320, + 'uni2129' : 8489, + 'uni25C5' : 9669, + 'uni0143' : 323, + 'uni0144' : 324, + 'uni0145' : 325, + 'uni0146' : 326, + 'uni0147' : 327, + 'uni210D' : 8461, + 'fraction' : 8260, + 'uni2031' : 8241, + 'uni2196' : 8598, + 'uni2035' : 8245, + 'uni24E6' : 9446, + 'uni016B' : 363, + 'uni24BA' : 9402, + 'uni266A' : 9834, + 'uni0116' : 278, + 'uni2115' : 8469, + 'registered' : 174, + 'J' : 74, + 'uni25DF' : 9695, + 'uni25CE' : 9678, + 'uni273D' : 10045, + 'dieresis' : 168, + 'uni212B' : 8491, + 'uni0114' : 276, + 'uni212D' : 8493, + 'uni212E' : 8494, + 'uni212F' : 8495, + 'uni014A' : 330, + 'uni014B' : 331, + 'uni014C' : 332, + 'uni014D' : 333, + 'uni014E' : 334, + 'uni014F' : 335, + 'uni025E' : 606, + 'uni24E8' : 9448, + 'uni0111' : 273, + 'uni24E9' : 9449, + 'Ograve' : 210, + 'j' : 106, + 'uni2195' : 8597, + 'uni2194' : 8596, + 'uni2197' : 8599, + 'uni2037' : 8247, + 'uni2191' : 8593, + 'uni2190' : 8592, + 'uni2193' : 8595, + 'uni2192' : 8594, + 'uni29FA' : 10746, + 'uni2713' : 10003, + 'z' : 122, + 'uni2199' : 8601, + 'uni2198' : 8600, + 'uni2667' : 9831, + 'ae' : 230, + 'uni0448' : 1096, + 'semicolon' : 59, + 'uni2666' : 9830, + 'uni038F' : 911, + 'uni0444' : 1092, + 'uni0447' : 1095, + 'uni038E' : 910, + 'uni0441' : 1089, + 'uni038C' : 908, + 'uni0443' : 1091, + 'uni038A' : 906, + 'uni0250' : 592, + 'uni0251' : 593, + 'uni0252' : 594, + 'uni0253' : 595, + 'uni0254' : 596, + 'at' : 64, + 'uni0256' : 598, + 'uni0257' : 599, + 'uni0167' : 359, + 'uni0259' : 601, + 'uni228C' : 8844, + 'uni2662' : 9826, + 'uni0319' : 793, + 'uni0318' : 792, + 'uni24BC' : 9404, + 'uni0402' : 1026, + 'uni22EF' : 8943, + 'Iacute' : 205, + 'uni22ED' : 8941, + 'uni22EE' : 8942, + 'uni0311' : 785, + 'uni0310' : 784, + 'uni21E8' : 8680, + 'uni0312' : 786, + 'percent' : 37, + 'uni0317' : 791, + 'uni0316' : 790, + 'uni21D6' : 8662, + 'uni21D7' : 8663, + 'uni21D4' : 8660, + 'uni21D5' : 8661, + 'uni21D2' : 8658, + 'uni21D3' : 8659, + 'uni21D0' : 8656, + 'uni2138' : 8504, + 'uni2270' : 8816, + 'uni2271' : 8817, + 'uni2272' : 8818, + 'uni2273' : 8819, + 'uni2274' : 8820, + 'uni2275' : 8821, + 'bracketright' : 93, + 'uni21D9' : 8665, + 'uni21DF' : 8671, + 'uni21DD' : 8669, + 'uni21DE' : 8670, + 'AE' : 198, + 'uni03AE' : 942, + 'uni227A' : 8826, + 'uni227B' : 8827, + 'uni227C' : 8828, + 'asterisk' : 42, + 'aacute' : 225, + 'uni226F' : 8815, + 'uni22E2' : 8930, + 'uni0386' : 902, + 'uni22E0' : 8928, + 'uni22E1' : 8929, + 'U' : 85, + 'uni22E7' : 8935, + 'uni22E4' : 8932, + 'uni0387' : 903, + 'uni031A' : 794, + 'eacute' : 233, + 'uni22E8' : 8936, + 'uni22E9' : 8937, + 'uni24D8' : 9432, + 'uni025A' : 602, + 'uni025B' : 603, + 'uni025C' : 604, + 'e' : 101, + 'uni0128' : 296, + 'uni025F' : 607, + 'uni2665' : 9829, + 'thorn' : 254, + 'uni0129' : 297, + 'uni253C' : 9532, + 'uni25D7' : 9687, + 'u' : 117, + 'uni0388' : 904, + 'uni0389' : 905, + 'uni0255' : 597, + 'uni0171' : 369, + 'uni0384' : 900, + 'uni0385' : 901, + 'uni044A' : 1098, + 'uni252C' : 9516, + 'uni044C' : 1100, + 'uni044B' : 1099 +} + +uni2type1 = dict([(v,k) for k,v in type12uni.items()]) + tex2uni = { 'widehat' : 0x0302, 'widetilde' : 0x0303, From 7caaccd1262a3a20277d8640bd430bbaaea64532 Mon Sep 17 00:00:00 2001 From: "Alex C. Szatmary" Date: Wed, 7 Sep 2011 18:07:59 -0400 Subject: [PATCH 126/214] Fix download path for libpng 1.5.1 in make.osx --- make.osx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.osx b/make.osx index 4639eac796ba..31fbc925bad2 100644 --- a/make.osx +++ b/make.osx @@ -25,7 +25,7 @@ ZLIBURL=http://sourceforge.net/projects/libpng/files/zlib/${ZLIBVERSION}/${ZLIBF PNGFILE=libpng-${PNGVERSION}.tar.gz PNGDIR=$(basename $(basename ${PNGFILE})) -PNGURL=http://sourceforge.net/projects/libpng/files/libpng15/${PNGVERSION}/${PNGFILE}/download +PNGURL=http://sourceforge.net/projects/libpng/files/libpng15/older-releases/${PNGVERSION}/${PNGFILE}/download FREETYPEFILE=freetype-${FREETYPEVERSION}.tar.bz2 FREETYPEDIR=$(basename $(basename ${FREETYPEFILE})) From af5aeb3af82dceb68488cd3dbeeb090b4a03d490 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Fri, 9 Sep 2011 13:04:44 -0500 Subject: [PATCH 127/214] reused cached excel fonts to avoid max font bug w/ rec2excel --- lib/matplotlib/mlab.py | 14 ++++++++++++++ lib/mpl_toolkits/exceltools.py | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index 21d89140b42e..fb88cc117c04 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -2350,6 +2350,13 @@ def toval(self, x): def fromstr(self, s): return s + + def __hash__(self): + """ + override the hash function of any of the formatters, so that we don't create duplicate excel format styles + """ + return hash(self.__class__) + class FormatString(FormatObj): def tostr(self, x): val = repr(x) @@ -2378,6 +2385,9 @@ def __init__(self, precision=4, scale=1.): self.precision = precision self.scale = scale + def __hash__(self): + return hash((self.__class__, self.precision, self.scale)) + def toval(self, x): if x is not None: x = x * self.scale @@ -2425,6 +2435,10 @@ class FormatDate(FormatObj): def __init__(self, fmt): self.fmt = fmt + def __hash__(self): + return hash((self.__class__, self.fmt)) + + def toval(self, x): if x is None: return 'None' return x.strftime(self.fmt) diff --git a/lib/mpl_toolkits/exceltools.py b/lib/mpl_toolkits/exceltools.py index ed1218a98fee..329e8c9dd8df 100644 --- a/lib/mpl_toolkits/exceltools.py +++ b/lib/mpl_toolkits/exceltools.py @@ -1,6 +1,6 @@ """ Some io tools for excel -- requires xlwt - +l Example usage: import matplotlib.mlab as mlab @@ -33,9 +33,16 @@ def xlformat_factory(format): copy the format, perform any overrides, and attach an xlstyle instance copied format is returned """ - format = copy.deepcopy(format) + #if we have created an excel format already using this format, + #don't recreate it; mlab.FormatObj override has to make objs with + #the same props hash to the same value + key = hash(format) + fmt_ = xlformat_factory.created_formats.get(key) + if fmt_ is not None: + return fmt_ + format = copy.deepcopy(format) xlstyle = excel.XFStyle() if isinstance(format, mlab.FormatPercent): @@ -55,8 +62,12 @@ def xlformat_factory(format): format.xlstyle = xlstyle + xlformat_factory.created_formats[ key ] = format + return format +xlformat_factory.created_formats = {} + def rec2excel(r, ws, formatd=None, rownum=0, colnum=0, nanstr='NaN', infstr='Inf'): """ save record array r to excel xlwt worksheet ws From 8bde1109b4e879e11b84c525d3af33ab99b11ac5 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Fri, 9 Sep 2011 13:22:54 -0500 Subject: [PATCH 128/214] fix extra character typo --- lib/mpl_toolkits/exceltools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpl_toolkits/exceltools.py b/lib/mpl_toolkits/exceltools.py index 329e8c9dd8df..0f26c8aa4d57 100644 --- a/lib/mpl_toolkits/exceltools.py +++ b/lib/mpl_toolkits/exceltools.py @@ -1,6 +1,6 @@ """ Some io tools for excel -- requires xlwt -l + Example usage: import matplotlib.mlab as mlab From 5552977439902504002c5234f8ea6ad2d8e07495 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sat, 10 Sep 2011 12:37:52 -0500 Subject: [PATCH 129/214] Fixed variable typo in axes.ticklabel_format() for useLocale --- lib/matplotlib/axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index b13e55bca9a6..ea8657b186e9 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2127,7 +2127,7 @@ def ticklabel_format(self, **kwargs): style = kwargs.pop('style', '').lower() scilimits = kwargs.pop('scilimits', None) useOffset = kwargs.pop('useOffset', None) - use_locale = kwargs.pop('useLocale', None) + useLocale = kwargs.pop('useLocale', None) axis = kwargs.pop('axis', 'both').lower() if scilimits is not None: try: From 6024edfdf85d9b9b15f194e0b76d24f20dfefcb6 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 11 Sep 2011 10:30:29 -1000 Subject: [PATCH 130/214] clabel: fix dpi bug, improve estimate of text width The dpi bug fix is based on a patch proposed by Jae-Joon Lee. In addition, the non-mathtext estimate of width is changed to account for character width being smaller than the font size. Other changes fix typos and docstrings, and streamline a small amount of code. --- lib/matplotlib/contour.py | 69 ++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 21d5599cc5d0..0ad28a9704e1 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -208,7 +208,7 @@ def clabel(self, *args, **kwargs): else: self.labels(inline,inline_spacing) - # Hold on to some old attribute names. These are depricated and will + # Hold on to some old attribute names. These are deprecated and will # be removed in the near future (sometime after 2008-08-01), but keeping # for now for backwards compatibility self.cl = self.labelTexts @@ -219,11 +219,11 @@ def clabel(self, *args, **kwargs): return self.labelTextsList - def print_label(self, linecontour,labelwidth): - "if contours are too short, don't plot a label" + def print_label(self, linecontour, labelwidth): + "Return False if contours are too short for a label." lcsize = len(linecontour) if lcsize > 10 * labelwidth: - return 1 + return True xmax = np.amax(linecontour[:,0]) xmin = np.amin(linecontour[:,0]) @@ -232,30 +232,29 @@ def print_label(self, linecontour,labelwidth): lw = labelwidth if (xmax - xmin) > 1.2* lw or (ymax - ymin) > 1.2 * lw: - return 1 + return True else: - return 0 - - def too_close(self, x,y, lw): - "if there's a label already nearby, find a better place" - if self.labelXYs != []: - dist = [np.sqrt((x-loc[0]) ** 2 + (y-loc[1]) ** 2) - for loc in self.labelXYs] - for d in dist: - if d < 1.2*lw: - return 1 - else: return 0 - else: return 0 + return False + + def too_close(self, x, y, lw): + "Return True if a label is already near this location." + for loc in self.labelXYs: + d = np.sqrt((x-loc[0]) ** 2 + (y-loc[1]) ** 2) + if d < 1.2*lw: + return True + return False def get_label_coords(self, distances, XX, YY, ysize, lw): - """ labels are ploted at a location with the smallest - dispersion of the contour from a straight line - unless there's another label nearby, in which case - the second best place on the contour is picked up - if there's no good place a label isplotted at the - beginning of the contour """ - + Return x, y, and the index of a label location. + + Labels are plotted at a location with the smallest + deviation of the contour from a straight line + unless there is another label nearby, in which case + the next best place on the contour is picked up. + If all such candidates are rejected, the beginning + of the contour is chosen. + """ hysize = int(ysize/2) adist = np.argsort(distances) @@ -263,15 +262,16 @@ def get_label_coords(self, distances, XX, YY, ysize, lw): x, y = XX[ind][hysize], YY[ind][hysize] if self.too_close(x,y, lw): continue - else: - return x,y, ind + return x,y, ind ind = adist[0] x, y = XX[ind][hysize], YY[ind][hysize] return x,y, ind def get_label_width(self, lev, fmt, fsize): - "get the width of the label in points" + """ + Return the width of the label in points. + """ if not cbook.is_string_like(lev): lev = self.get_text(lev, fmt) @@ -286,7 +286,7 @@ def get_label_width(self, lev, fmt, fsize): img, _ = self._mathtext_parser.parse(lev, dpi=72, prop=self.labelFontProps) lw = img.get_width() # at dpi=72, the units are PostScript points else: - lw = (len(lev)) * fsize + lw = (len(lev)) * fsize * 0.6 # width is much less than "font size" return lw @@ -295,6 +295,8 @@ def get_real_label_width( self, lev, fmt, fsize ): This computes actual onscreen label width. This uses some black magic to determine onscreen extent of non-drawn label. This magic may not be very robust. + + This method is not being used, and may be modified or removed. """ # Find middle of axes xx = np.mean( np.asarray(self.ax.axis()).reshape(2,2), axis=1 ) @@ -334,9 +336,9 @@ def get_text(self, lev, fmt): return fmt%lev def locate_label(self, linecontour, labelwidth): - """find a good place to plot a label (relatively flat - part of the contour) and the angle of rotation for the - text object + """ + Find a good place to plot a label (relatively flat + part of the contour). """ nsize= len(linecontour) @@ -470,10 +472,10 @@ def calc_label_rot_and_inline( self, slc, ind, lw, lc=None, spacing=5 ): # The current implementation removes contours completely # covered by labels. Uncomment line below to keep - # original contour if this is the preferred behavoir. + # original contour if this is the preferred behavior. #if not len(nlc): nlc = [ lc ] - return (rotation,nlc) + return rotation, nlc def _get_label_text(self,x,y,rotation): dx,dy = self.ax.transData.inverted().transform_point((x,y)) @@ -551,6 +553,7 @@ def labels(self, inline, inline_spacing): con = self.collections[icon] trans = con.get_transform() lw = self.get_label_width(lev, self.labelFmt, fsize) + lw *= self.ax.figure.dpi/72.0 # scale to screen coordinates additions = [] paths = con.get_paths() for segNum, linepath in enumerate(paths): From 1e86b8a265d68aa0ceb061d89da943627e5d150a Mon Sep 17 00:00:00 2001 From: Kevin Davies Date: Mon, 12 Sep 2011 07:51:17 -0500 Subject: [PATCH 131/214] add sankey module and new demo --- examples/api/sankey_demo.py | 399 ++++++------- examples/api/sankey_demo_old.py | 189 +++++++ lib/matplotlib/sankey.py | 953 ++++++++++++++++++++++++++++++++ 3 files changed, 1353 insertions(+), 188 deletions(-) create mode 100644 examples/api/sankey_demo_old.py create mode 100644 lib/matplotlib/sankey.py diff --git a/examples/api/sankey_demo.py b/examples/api/sankey_demo.py index c10243e48498..5845cb37f1e7 100644 --- a/examples/api/sankey_demo.py +++ b/examples/api/sankey_demo.py @@ -1,188 +1,211 @@ -#!/usr/bin/env python - -__author__ = "Yannick Copin " -__version__ = "Time-stamp: <10/02/2010 16:49 ycopin@lyopc548.in2p3.fr>" - -import numpy as N - -def sankey(ax, - outputs=[100.], outlabels=None, - inputs=[100.], inlabels='', - dx=40, dy=10, outangle=45, w=3, inangle=30, offset=2, **kwargs): - """Draw a Sankey diagram. - - outputs: array of outputs, should sum up to 100% - outlabels: output labels (same length as outputs), - or None (use default labels) or '' (no labels) - inputs and inlabels: similar for inputs - dx: horizontal elongation - dy: vertical elongation - outangle: output arrow angle [deg] - w: output arrow shoulder - inangle: input dip angle - offset: text offset - **kwargs: propagated to Patch (e.g. fill=False) - - Return (patch,[intexts,outtexts]).""" - - import matplotlib.patches as mpatches - from matplotlib.path import Path - - outs = N.absolute(outputs) - outsigns = N.sign(outputs) - outsigns[-1] = 0 # Last output - - ins = N.absolute(inputs) - insigns = N.sign(inputs) - insigns[0] = 0 # First input - - assert sum(outs)==100, "Outputs don't sum up to 100%" - assert sum(ins)==100, "Inputs don't sum up to 100%" - - def add_output(path, loss, sign=1): - h = (loss/2+w)*N.tan(outangle/180.*N.pi) # Arrow tip height - move,(x,y) = path[-1] # Use last point as reference - if sign==0: # Final loss (horizontal) - path.extend([(Path.LINETO,[x+dx,y]), - (Path.LINETO,[x+dx,y+w]), - (Path.LINETO,[x+dx+h,y-loss/2]), # Tip - (Path.LINETO,[x+dx,y-loss-w]), - (Path.LINETO,[x+dx,y-loss])]) - outtips.append((sign,path[-3][1])) - else: # Intermediate loss (vertical) - path.extend([(Path.CURVE4,[x+dx/2,y]), - (Path.CURVE4,[x+dx,y]), - (Path.CURVE4,[x+dx,y+sign*dy]), - (Path.LINETO,[x+dx-w,y+sign*dy]), - (Path.LINETO,[x+dx+loss/2,y+sign*(dy+h)]), # Tip - (Path.LINETO,[x+dx+loss+w,y+sign*dy]), - (Path.LINETO,[x+dx+loss,y+sign*dy]), - (Path.CURVE3,[x+dx+loss,y-sign*loss]), - (Path.CURVE3,[x+dx/2+loss,y-sign*loss])]) - outtips.append((sign,path[-5][1])) - - def add_input(path, gain, sign=1): - h = (gain/2)*N.tan(inangle/180.*N.pi) # Dip depth - move,(x,y) = path[-1] # Use last point as reference - if sign==0: # First gain (horizontal) - path.extend([(Path.LINETO,[x-dx,y]), - (Path.LINETO,[x-dx+h,y+gain/2]), # Dip - (Path.LINETO,[x-dx,y+gain])]) - xd,yd = path[-2][1] # Dip position - indips.append((sign,[xd-h,yd])) - else: # Intermediate gain (vertical) - path.extend([(Path.CURVE4,[x-dx/2,y]), - (Path.CURVE4,[x-dx,y]), - (Path.CURVE4,[x-dx,y+sign*dy]), - (Path.LINETO,[x-dx-gain/2,y+sign*(dy-h)]), # Dip - (Path.LINETO,[x-dx-gain,y+sign*dy]), - (Path.CURVE3,[x-dx-gain,y-sign*gain]), - (Path.CURVE3,[x-dx/2-gain,y-sign*gain])]) - xd,yd = path[-4][1] # Dip position - indips.append((sign,[xd,yd+sign*h])) - - outtips = [] # Output arrow tip dir. and positions - urpath = [(Path.MOVETO,[0,100])] # 1st point of upper right path - lrpath = [(Path.LINETO,[0,0])] # 1st point of lower right path - for loss,sign in zip(outs,outsigns): - add_output(sign>=0 and urpath or lrpath, loss, sign=sign) - - indips = [] # Input arrow tip dir. and positions - llpath = [(Path.LINETO,[0,0])] # 1st point of lower left path - ulpath = [(Path.MOVETO,[0,100])] # 1st point of upper left path - for gain,sign in zip(ins,insigns)[::-1]: - add_input(sign<=0 and llpath or ulpath, gain, sign=sign) - - def revert(path): - """A path is not just revertable by path[::-1] because of Bezier - curves.""" - rpath = [] - nextmove = Path.LINETO - for move,pos in path[::-1]: - rpath.append((nextmove,pos)) - nextmove = move - return rpath - - # Concatenate subpathes in correct order - path = urpath + revert(lrpath) + llpath + revert(ulpath) - - codes,verts = zip(*path) - verts = N.array(verts) - - # Path patch - path = Path(verts,codes) - patch = mpatches.PathPatch(path, **kwargs) - ax.add_patch(patch) - - if False: # DEBUG - print "urpath", urpath - print "lrpath", revert(lrpath) - print "llpath", llpath - print "ulpath", revert(ulpath) - - xs,ys = zip(*verts) - ax.plot(xs,ys,'go-') - - # Labels - - def set_labels(labels,values): - """Set or check labels according to values.""" - if labels=='': # No labels - return labels - elif labels is None: # Default labels - return [ '%2d%%' % val for val in values ] - else: - assert len(labels)==len(values) - return labels - - def put_labels(labels,positions,output=True): - """Put labels to positions.""" - texts = [] - lbls = output and labels or labels[::-1] - for i,label in enumerate(lbls): - s,(x,y) = positions[i] # Label direction and position - if s==0: - t = ax.text(x+offset,y,label, - ha=output and 'left' or 'right', va='center') - elif s>0: - t = ax.text(x,y+offset,label, ha='center', va='bottom') - else: - t = ax.text(x,y-offset,label, ha='center', va='top') - texts.append(t) - return texts - - outlabels = set_labels(outlabels, outs) - outtexts = put_labels(outlabels, outtips, output=True) - - inlabels = set_labels(inlabels, ins) - intexts = put_labels(inlabels, indips, output=False) - - # Axes management - ax.set_xlim(verts[:,0].min()-dx, verts[:,0].max()+dx) - ax.set_ylim(verts[:,1].min()-dy, verts[:,1].max()+dy) - ax.set_aspect('equal', adjustable='datalim') - - return patch,[intexts,outtexts] - -if __name__=='__main__': - - import matplotlib.pyplot as P - - outputs = [10.,-20.,5.,15.,-10.,40.] - outlabels = ['First','Second','Third','Fourth','Fifth','Hurray!'] - outlabels = [ s+'\n%d%%' % abs(l) for l,s in zip(outputs,outlabels) ] - - inputs = [60.,-25.,15.] - - fig = P.figure() - ax = fig.add_subplot(1,1,1, xticks=[],yticks=[], - title="Sankey diagram" - ) - - patch,(intexts,outtexts) = sankey(ax, outputs=outputs, outlabels=outlabels, - inputs=inputs, inlabels=None, - fc='g', alpha=0.2) - outtexts[1].set_color('r') - outtexts[-1].set_fontweight('bold') - - P.show() +"""Demonstrate the Sankey class. +""" +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib.sankey import Sankey +from itertools import cycle + + +"""Demonstrate the Sankey class. +""" +import matplotlib.pyplot as plt +from itertools import cycle + +# Example 1 -- Mostly defaults +# This demonstrates how to create a simple diagram by implicitly calling the +# Sankey.add() method and by appending finish() to the call to the class. +Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], + labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], + orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() +plt.title("The default settings produce a diagram like this.") +# Notice: +# 1. Axes weren't provided when Sankey() was instantiated, so they were +# created automatically. +# 2. The scale argument wasn't necessary since the data was already +# normalized. +# 3. By default, the lengths of the paths are justified. + +# Example 2 +# This demonstrates: +# 1. Setting one path longer than the others +# 2. Placing a label in the middle of the diagram +# 3. Using the the scale argument to normalize the flows +# 4. Implicitly passing keyword arguments to PathPatch() +# 5. Changing the angle of the arrow heads +# 6. Changing the offset between the tips of the paths and their labels +# 7. Formatting the numbers in the path labels and the associated unit +# 8. Changing the appearance of the patch and the labels after the figure +# is created +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Flow Diagram of a Widget") +sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, + format='%.0f', unit='%') +sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], + labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', + 'Fifth', 'Hurray!'], + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], + pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, + 0.25], + patchlabel="Widget\nA", + alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() +diagrams = sankey.finish() +diagrams[0].patch.set_facecolor('#37c959') +diagrams[0].texts[-1].set_color('r') +diagrams[0].text.set_fontweight('bold') +# Without namedtuple: +#diagrams[0][0].set_facecolor('#37c959') +#diagrams[0][5][-1].set_color('r') +#diagrams[0][4].set_fontweight('bold') +# Notice: +# 1. Since the sum of the flows isn't zero, the width of the trunk isn't +# uniform. A message is given in the terminal window. +# 2. The second flow doesn't appear because its value is zero. A messsage +# is given in the terminal window. + +# Example 3 +# This demonstrates: +# 1. Connecting two systems +# 2. Turning off the labels of the quantities +# 3. Adding a legend +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") +flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] +sankey = Sankey(ax=ax, unit=None) +sankey.add(flows=flows, label='one', + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) +sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', + orientations=[-1, -1, -1], prior=0, connect=(0, 0)) +diagrams = sankey.finish() +diagrams[-1].patch.set_hatch('/') +# Without namedtuple: +#diagrams[-1][0].set_hatch('/') + +plt.legend(loc='best') +# Notice that only one connection is specified, but the systems form a +# circuit since: (1) the lengths of the paths are justified and (2) the +# orientation and ordering of the flows is mirrored. + +# Example 4 +# This tests a long chain of connections. +links_per_side = 6 +def side(sankey, n=1): + prior = len(sankey.diagrams) + colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) + for i in range(0, 2*n, 2): + sankey.add(flows=[1, -1], orientations=[-1, -1], + patchlabel=str(prior+i), facecolor=colors.next(), + prior=prior+i-1, connect=(1, 0), alpha=0.5) + sankey.add(flows=[1, -1], orientations=[1, 1], + patchlabel=str(prior+i+1), facecolor=colors.next(), + prior=prior+i, connect=(1, 0), alpha=0.5) +def corner(sankey): + prior = len(sankey.diagrams) + sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel=str(prior), facecolor='k', + prior=prior-1, connect=(1, 0), alpha=0.5) +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Why would you want to do this?" \ + "\n(But you could.)") +sankey = Sankey(ax=ax, unit=None) +sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel="0", facecolor='k', + rotation=45) +side(sankey, n=links_per_side) +corner(sankey) +side(sankey, n=links_per_side) +corner(sankey) +side(sankey, n=links_per_side) +corner(sankey) +side(sankey, n=links_per_side) +sankey.finish() +# Notice: +# 1. The alignment doesn't drift significantly (if at all; with 16007 +# subdiagrams there is still closure). +# 2. The first diagram is rotated 45 degrees, so all other diagrams are +# rotated accordingly. + +# Example 5 +# This demonstrates a practical example -- a Rankine power cycle. +fig = plt.figure(figsize=(8, 12)) +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" + + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") +Hdot = np.array([260.431, 35.078, 180.794, 221.115, 22.700, + 142.361, 10.193, 10.210, 43.670, 44.312, + 68.631, 10.758, 10.758, 0.017, 0.642, + 232.121, 44.559, 100.613, 132.168])*1.0e6 # W +sankey = Sankey(ax=ax, format='%.3G', unit='W', gap=0.5, scale=1.0/Hdot[0]) +# Shared copy: +#Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, +# 142.361, 10.193, 10.210, 43.670, 44.312, +# 68.631, 10.758, 10.758, 0.017, 0.642, +# 232.121, 44.559, 100.613, 132.168] # MW +#sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) +sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', + flows=[Hdot[13], Hdot[6], -Hdot[7]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.883, 0.25], + orientations=[1, -1, 0]) +sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', + flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], + labels=[None, '', None, None], + pathlengths=[0.25, 0.25, 1.93, 0.25], + orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) +sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', + flows=[Hdot[14], Hdot[8], -Hdot[9]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.25, 0.25], + orientations=[1, 0, 0], prior=1, connect=(3, 1)) +sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', + flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], + pathlengths=[0.25, 1.543, 0.25, 0.25], + labels=['', '', None, None], + orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) +sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, + flows=[Hdot[11], -Hdot[12]], + labels=['\n', None], + pathlengths=[1.0, 1.01], + orientations=[1, 1], prior=3, connect=(2, 0)) +sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', + flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], + labels=['Heat rate', '', '', None, None], + pathlengths=0.25, + orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) +sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', + flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], + labels=['', None, None, None], + pathlengths=[0.25, 0.153, 1.543, 0.25], + orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) +sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', + flows=[Hdot[2], -Hdot[2]], + labels=[None, None], + pathlengths=[0.725, 0.25], + orientations=[-1, 0], prior=6, connect=(3, 0)) +sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', + flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], + labels=[None, 'Shaft power', None, '', 'Shaft power'], + pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], + orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) +sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, + flows=[Hdot[5], -Hdot[18], -Hdot[6]], + labels=['', 'Heat rate', None], + pathlengths=[0.45, 0.25, 0.883], + orientations=[-1, 1, 0], prior=8, connect=(2, 0)) +diagrams = sankey.finish() +for diagram in diagrams: + diagram.text.set_fontweight('bold') + diagram.text.set_fontsize('10') + for text in diagram.texts: + # Without namedtuple: + #diagram[4].set_fontweight('bold') + #diagram[4].set_fontsize('10') + #for text in diagram[5]: + text.set_fontsize('10') +# Notice that the explicit connections are handled automatically, but the +# implicit ones currently are not. The lengths of the paths and the trunks +# must be adjusted manually, and that is a bit tricky. + +plt.show() diff --git a/examples/api/sankey_demo_old.py b/examples/api/sankey_demo_old.py new file mode 100644 index 000000000000..fac4f4452e5d --- /dev/null +++ b/examples/api/sankey_demo_old.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python + +__author__ = "Yannick Copin " +__version__ = "Time-stamp: <10/02/2010 16:49 ycopin@lyopc548.in2p3.fr>" + +import numpy as N + +def sankey(ax, + outputs=[100.], outlabels=None, + inputs=[100.], inlabels='', + dx=40, dy=10, outangle=45, w=3, inangle=30, offset=2, **kwargs): + """Draw a Sankey diagram. + +outputs: array of outputs, should sum up to 100% +outlabels: output labels (same length as outputs), +or None (use default labels) or '' (no labels) +inputs and inlabels: similar for inputs +dx: horizontal elongation +dy: vertical elongation +outangle: output arrow angle [deg] +w: output arrow shoulder +inangle: input dip angle +offset: text offset +**kwargs: propagated to Patch (e.g. fill=False) + +Return (patch,[intexts,outtexts]).""" + + import matplotlib.patches as mpatches + from matplotlib.path import Path + + outs = N.absolute(outputs) + outsigns = N.sign(outputs) + outsigns[-1] = 0 # Last output + + ins = N.absolute(inputs) + insigns = N.sign(inputs) + insigns[0] = 0 # First input + + assert sum(outs)==100, "Outputs don't sum up to 100%" + assert sum(ins)==100, "Inputs don't sum up to 100%" + + def add_output(path, loss, sign=1): + h = (loss/2+w)*N.tan(outangle/180.*N.pi) # Arrow tip height + move,(x,y) = path[-1] # Use last point as reference + if sign==0: # Final loss (horizontal) + path.extend([(Path.LINETO,[x+dx,y]), + (Path.LINETO,[x+dx,y+w]), + (Path.LINETO,[x+dx+h,y-loss/2]), # Tip + (Path.LINETO,[x+dx,y-loss-w]), + (Path.LINETO,[x+dx,y-loss])]) + outtips.append((sign,path[-3][1])) + else: # Intermediate loss (vertical) + path.extend([(Path.CURVE4,[x+dx/2,y]), + (Path.CURVE4,[x+dx,y]), + (Path.CURVE4,[x+dx,y+sign*dy]), + (Path.LINETO,[x+dx-w,y+sign*dy]), + (Path.LINETO,[x+dx+loss/2,y+sign*(dy+h)]), # Tip + (Path.LINETO,[x+dx+loss+w,y+sign*dy]), + (Path.LINETO,[x+dx+loss,y+sign*dy]), + (Path.CURVE3,[x+dx+loss,y-sign*loss]), + (Path.CURVE3,[x+dx/2+loss,y-sign*loss])]) + outtips.append((sign,path[-5][1])) + + def add_input(path, gain, sign=1): + h = (gain/2)*N.tan(inangle/180.*N.pi) # Dip depth + move,(x,y) = path[-1] # Use last point as reference + if sign==0: # First gain (horizontal) + path.extend([(Path.LINETO,[x-dx,y]), + (Path.LINETO,[x-dx+h,y+gain/2]), # Dip + (Path.LINETO,[x-dx,y+gain])]) + xd,yd = path[-2][1] # Dip position + indips.append((sign,[xd-h,yd])) + else: # Intermediate gain (vertical) + path.extend([(Path.CURVE4,[x-dx/2,y]), + (Path.CURVE4,[x-dx,y]), + (Path.CURVE4,[x-dx,y+sign*dy]), + (Path.LINETO,[x-dx-gain/2,y+sign*(dy-h)]), # Dip + (Path.LINETO,[x-dx-gain,y+sign*dy]), + (Path.CURVE3,[x-dx-gain,y-sign*gain]), + (Path.CURVE3,[x-dx/2-gain,y-sign*gain])]) + xd,yd = path[-4][1] # Dip position + indips.append((sign,[xd,yd+sign*h])) + + outtips = [] # Output arrow tip dir. and positions + urpath = [(Path.MOVETO,[0,100])] # 1st point of upper right path + lrpath = [(Path.LINETO,[0,0])] # 1st point of lower right path + for loss,sign in zip(outs,outsigns): + add_output(sign>=0 and urpath or lrpath, loss, sign=sign) + + indips = [] # Input arrow tip dir. and positions + llpath = [(Path.LINETO,[0,0])] # 1st point of lower left path + ulpath = [(Path.MOVETO,[0,100])] # 1st point of upper left path + for gain,sign in zip(ins,insigns)[::-1]: + add_input(sign<=0 and llpath or ulpath, gain, sign=sign) + + def revert(path): + """A path is not just revertable by path[::-1] because of Bezier +curves.""" + rpath = [] + nextmove = Path.LINETO + for move,pos in path[::-1]: + rpath.append((nextmove,pos)) + nextmove = move + return rpath + + # Concatenate subpathes in correct order + path = urpath + revert(lrpath) + llpath + revert(ulpath) + + codes,verts = zip(*path) + verts = N.array(verts) + + # Path patch + path = Path(verts,codes) + patch = mpatches.PathPatch(path, **kwargs) + ax.add_patch(patch) + + if False: # DEBUG + print "urpath", urpath + print "lrpath", revert(lrpath) + print "llpath", llpath + print "ulpath", revert(ulpath) + + xs,ys = zip(*verts) + ax.plot(xs,ys,'go-') + + # Labels + + def set_labels(labels,values): + """Set or check labels according to values.""" + if labels=='': # No labels + return labels + elif labels is None: # Default labels + return [ '%2d%%' % val for val in values ] + else: + assert len(labels)==len(values) + return labels + + def put_labels(labels,positions,output=True): + """Put labels to positions.""" + texts = [] + lbls = output and labels or labels[::-1] + for i,label in enumerate(lbls): + s,(x,y) = positions[i] # Label direction and position + if s==0: + t = ax.text(x+offset,y,label, + ha=output and 'left' or 'right', va='center') + elif s>0: + t = ax.text(x,y+offset,label, ha='center', va='bottom') + else: + t = ax.text(x,y-offset,label, ha='center', va='top') + texts.append(t) + return texts + + outlabels = set_labels(outlabels, outs) + outtexts = put_labels(outlabels, outtips, output=True) + + inlabels = set_labels(inlabels, ins) + intexts = put_labels(inlabels, indips, output=False) + + # Axes management + ax.set_xlim(verts[:,0].min()-dx, verts[:,0].max()+dx) + ax.set_ylim(verts[:,1].min()-dy, verts[:,1].max()+dy) + ax.set_aspect('equal', adjustable='datalim') + + return patch,[intexts,outtexts] + +if __name__=='__main__': + + import matplotlib.pyplot as P + + outputs = [10.,-20.,5.,15.,-10.,40.] + outlabels = ['First','Second','Third','Fourth','Fifth','Hurray!'] + outlabels = [ s+'\n%d%%' % abs(l) for l,s in zip(outputs,outlabels) ] + + inputs = [60.,-25.,15.] + + fig = P.figure() + ax = fig.add_subplot(1,1,1, xticks=[],yticks=[], + title="Sankey diagram" + ) + + patch,(intexts,outtexts) = sankey(ax, outputs=outputs, outlabels=outlabels, + inputs=inputs, inlabels=None, + fc='g', alpha=0.2) + outtexts[1].set_color('r') + outtexts[-1].set_fontweight('bold') + + P.show() + diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py new file mode 100644 index 000000000000..f142115fb0e7 --- /dev/null +++ b/lib/matplotlib/sankey.py @@ -0,0 +1,953 @@ +#!/usr/bin/env python +"""Module for creating Sankey diagrams using matplotlib +""" +__author__ = "Kevin L. Davies" +__credits__ = ["Yannick Copin"] +__license__ = "BSD" +__version__ = "2011/09/07" +# Original version by Yannick Copin (ycopin@ipnl.in2p3.fr) 10/2/2010, available +# at: +# http://matplotlib.sourceforge.net/examples/api/sankey_demo_old.html +# Modifications by Kevin Davies (kld@alumni.carnegiemellon.edu) 6/3/2011: +# --Used arcs for the curves (so that the widths of the paths are uniform) +# --Converted the function to a class and created methods to join +# multiple simple Sankey diagrams +# --Provided handling for cases where the total of the inputs isn't 100 +# Now, the default layout is based on the assumption that the inputs sum to +# 1. A scaling parameter can be used in other cases. +# --The call structure was changed to be more explicit about layout, including +# the length of the trunk, length of the paths, gap between the paths, and +# the margin around the diagram. +# --Allowed the lengths of paths to be adjusted individually, with an option +# to automatically justify them +# --The call structure was changed to make the specification of path +# orientation more flexible. Flows are passed through one array, with +# inputs being positive and outputs being negative. An orientation argment +# specifies the direction of the arrows. The "main" inputs/outputs are now +# specified via an orientation of 0, and there may be several of each. +# --Added assertions to catch common calling errors +# -Added the physical unit as a string argument to be used in the labels, so +# that the values of the flows can usually be applied automatically +# --Added an argument for a minimum magnitude below which flows are not shown +# --Added a tapered trunk in the case that the flows do not sum to 0 +# --Allowed the diagram to be rotated + +import numpy as np +from matplotlib.cbook import iterable, Bunch +from matplotlib.path import Path +from matplotlib.patches import PathPatch +from matplotlib.transforms import Affine2D +from matplotlib import verbose +#from collections import namedtuple +# Note: If you cannot use namedtuple (it was introduced in Python 2.6), then +# comment out the line above and switch out the commented code wherever +# "Without namedtuple" is written in the code that follows. + +# Angles (in deg/90) +RIGHT = 0 +UP = 1 +# LEFT = 2 +DOWN = 3 + + +# Container class for information about a simple Sankey diagram, i.e., one with +# inputs/outputs at a single hierarchial level +#SankeyInfo = namedtuple('SankeyInfo', 'patch flows angles tips text texts') +# Without namedtuple: Comment out the line above. +# See Sankey.finish() for a description of the fields. + + +class Sankey: + """Sankey diagram in matplotlib + + "Sankey diagrams are a specific type of flow diagram, in which the width of + the arrows is shown proportionally to the flow quantity. They are typically + used to visualize energy or material or cost transfers between processes." + --http://en.wikipedia.org/wiki/Sankey_diagram, accessed 6/1/2011 + """ + def _arc(self, quadrant=0, cw=True, radius=1, center=(0,0)): + """Return the codes and vertices for a rotated, scaled, and translated + 90 degree arc. + + quadrant: Uses 0-based indexing (0, 1, 2, or 3) + cw: If True, clockwise + center: (x, y) tuple of the arc's center + + Note: It would be possible to use matplotlib's transforms to do this, + but since the rotations is discrete, it's just as easy and maybe more + efficient to do it here. + """ + ARC_CODES = [Path.LINETO, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4] + # Vertices of a cubic Bezier curve approximating a 90 deg arc + # These can be determined by Path.arc(0,90). + ARC_VERTICES = np.array([[1.00000000e+00, 0.00000000e+00], + [1.00000000e+00, 2.65114773e-01], + [8.94571235e-01, 5.19642327e-01], + [7.07106781e-01, 7.07106781e-01], + [5.19642327e-01, 8.94571235e-01], + [2.65114773e-01, 1.00000000e+00], + #[6.12303177e-17, 1.00000000e+00]]) + [0.00000000e+00, 1.00000000e+00]]) + if quadrant == 0 or quadrant == 2: + if cw: + vertices = ARC_VERTICES + else: + vertices = ARC_VERTICES[:,::-1] # Swap x and y + elif quadrant == 1 or quadrant == 3: + # Negate x + if cw: + # Swap x and y + vertices = np.column_stack((-ARC_VERTICES[:,1], ARC_VERTICES[:,0])) + else: + vertices = np.column_stack((-ARC_VERTICES[:,0], ARC_VERTICES[:,1])) + if quadrant > 1: radius = -radius # Rotate 180 deg + return zip(ARC_CODES, + radius*vertices + np.tile(center, (ARC_VERTICES.shape[0], 1))) + + def _add_input(self, path, angle, flow, length): + """Add an input to a path and return its tip and label locations. + """ + if angle is None: + return [0, 0], [0, 0] + else: + (x, y) = path[-1][1] # Use the last point as a reference. + dipdepth = (flow / 2) * self.pitch + if angle == RIGHT: + x -= length + dip = [x + dipdepth, y + flow / 2.0] + path.extend([(Path.LINETO, [x, y]), + (Path.LINETO, dip), + (Path.LINETO, [x, y + flow]), + (Path.LINETO, [x+self.gap, y + flow])]) + label_location = [dip[0] - self.offset, dip[1]] + else: # Vertical + x -= self.gap + if angle==UP: sign = 1 + else: sign = -1 + + dip = [x - flow / 2, y - sign * (length - dipdepth)] + if angle==DOWN: q = 2 + else: q = 1 + + if self.radius: # Inner arc not needed if inner radius is zero + path.extend(self._arc(quadrant=q, + cw=angle==UP, + radius=self.radius, + center=(x + self.radius, + y - sign * self.radius))) + else: + path.append((Path.LINETO, [x, y])) + path.extend([(Path.LINETO, [x, y - sign * length]), + (Path.LINETO, dip), + (Path.LINETO, [x - flow, y - sign * length])]) + path.extend(self._arc(quadrant=q, + cw=angle==DOWN, + radius=flow + self.radius, + center=(x + self.radius, + y - sign * self.radius))) + path.append((Path.LINETO, [x - flow, y + sign * flow])) + label_location = [dip[0], dip[1] - sign * self.offset] + + return dip, label_location + + def _add_output(self, path, angle, flow, length): + """Append an output to a path and return its tip and label locations. + + Note: flow is negative for an output. + """ + if angle is None: + return [0, 0], [0, 0] + else: + (x, y) = path[-1][1] # Use the last point as a reference. + tipheight = (self.shoulder - flow / 2) * self.pitch + if angle == RIGHT: + x += length + tip = [x + tipheight, y + flow / 2.0] + path.extend([(Path.LINETO, [x, y]), + (Path.LINETO, [x, y + self.shoulder]), + (Path.LINETO, tip), + (Path.LINETO, [x, y - self.shoulder + flow]), + (Path.LINETO, [x, y + flow]), + (Path.LINETO, [x-self.gap, y + flow])]) + label_location = [tip[0] + self.offset, tip[1]] + else: # Vertical + x += self.gap + if angle==UP: sign = 1 + else: sign = -1 + + tip = [x - flow / 2.0, y + sign * (length + tipheight)] + if angle==UP: + q = 3 + else: + q = 0 + if self.radius: # Inner arc not needed if inner radius is zero + path.extend(self._arc(quadrant=q, + cw=angle==UP, + radius=self.radius, + center=(x - self.radius, + y + sign*self.radius))) + else: + path.append((Path.LINETO, [x, y])) + path.extend([(Path.LINETO, [x, y + sign * length]), + (Path.LINETO, [x - self.shoulder, y + sign * length]), + (Path.LINETO, tip), + (Path.LINETO, [x + self.shoulder - flow, y + sign * length]), + (Path.LINETO, [x - flow, y + sign * length])]) + path.extend(self._arc(quadrant=q, + cw=angle==DOWN, + radius=self.radius - flow, + center=(x - self.radius, + y + sign * self.radius))) + path.append((Path.LINETO, [x - flow, y + sign * flow])) + label_location = [tip[0], tip[1] + sign * self.offset] + return tip, label_location + + def _revert(self, path, first_action=Path.LINETO): + """A path is not simply revertable by path[::-1] since the code + specifies an action to take from the _previous_ point. + """ + reverse_path = [] + next_code = first_action + for code,position in path[::-1]: + reverse_path.append((next_code, position)) + next_code = code + return reverse_path + # This might be more efficient, but it fails because 'tuple' object + # doesn't support item assignment: + #path[1] = path[1][-1:0:-1] + #path[1][0] = first_action + #path[2] = path[2][::-1] + #return path + + def add(self, patchlabel='', + flows=np.array([1.0,-1.0]), orientations=[0,0], labels='', + trunklength=1.0, pathlengths=0.25, prior=None, connect=(0,0), + rotation=0, **kwargs): + """Add a simple Sankey diagram with flows at the same hierarchial level. + + patchlabel: Label to be placed at the center of the diagram + Note: label (not patchlabel) will be passed the patch + through **kwargs below and can be used to create an + entry in the legend. + flows: Array of flow values + By convention, inputs are positive and outputs are + negative. + orientations: List of orientations of the paths. + The values should be 1 (from/to the top), 0 (from/to a + the left or right), or -1 (from/to the bottom). If 0, + inputs will break in from the left and outputs will break + away to the right. + labels: List of specifications of the labels for the flows + Each value may be None (no labels), '' (just label the + quantities), or a labeling string. If a single value is + provided, it will be applied to all flows. If an entry + is a non-empty string, then the quantity for the + corresponding flow will be shown below the string. + However, if the unit of the main diagram is None, then + quantities are never shown, regardless of the value of + this argument. + trunklength: Length between the bases of the input and output groups + pathlengths: List of lengths of the arrows before break-in or after + break-away + If a single value is given, then it will be applied to + the first (inside) paths on the top and bottom, and the + length of all other arrows will be justified accordingly. + Ths pathlengths are not applied to the hoizontal inputs + and outputs. + prior: Index of the prior diagram to which this diagram should + be connected + connect: A (prior, this) tuple indexing the flow of the prior + diagram and the flow of this diagram which should be + connected + If this is the first diagram or prior is None, connect + will be ignored. + rotation: Angle of rotation of the diagram [deg] + rotation is ignored if this diagram is connected to an + existing one (using prior and connect). The + interpretation of the orientations argument will be + rotated accordingly (e.g., if rotation == 90, an + orientations entry of 1 means to/from the left). + **kwargs: Propagated to matplotlib.patches.PathPatch (e.g., + fill=False, label="A legend entry") + By default, facecolor='#bfd1d4' (light blue) and + lineweight=0.5. + + The indexing parameters (prior and connect) are zero-based. + + The flows are placed along the top of the diagram from the inside out in + order of their index within the flows list or array. They are placed + along the sides of the diagram from the top down and along the bottom + from the outside in. + + If the the sum of the inputs and outputs is not zero, the discrepancy + will show as a cubic Bezier curve along the top and bottom edges of the + trunk. + """ + # Check and preprocess the arguments. + flows = np.array(flows) + n = flows.shape[0] # Number of flows + if rotation == None: + rotation = 0 + else: + rotation /= 90.0 # In the code below, angles are expressed in deg/90. + assert len(orientations) == n, \ + "orientations and flows must have the same length.\n" \ + + "orientations has length " + str(len(orientations)) \ + + ", but flows has length " + str(n) + "." + if getattr(labels, '__iter__', False): + # iterable() isn't used because it would give True if labels is a string. + assert len(labels) == n, \ + "If labels is a list, then labels and flows must " \ + + "have the same length.\nlabels has length " \ + + str(len(labels)) + ", but flows has length " + str(n) + "." + else: + labels = [labels]*n + assert trunklength >= 0, \ + "trunklength is negative.\n" \ + + "This isn't allowed because it would cause poor layout." + if np.absolute(np.sum(flows)) > self.tolerance: + verbose.report("The sum of the flows is nonzero (" \ + + str(np.sum(flows)) + ").\nIs the system not at steady state?", + 'helpful') + scaled_flows = self.scale*flows + gain = sum(max(flow, 0) for flow in scaled_flows) + loss = sum(min(flow, 0) for flow in scaled_flows) + if not (0.5 <= gain <= 2.0): + verbose.report("The scaled sum of the inputs is " + str(gain) \ + + ".\nThis may cause poor layout.\nConsider changing the " \ + "scale so that the scaled sum is approximately 1.0.", + 'helpful') + if not (-2.0 <= loss <= -0.5): + verbose.report("The scaled sum of the outputs is " + str(gain) \ + + ".\nThis may cause poor layout.\nConsider changing the " \ + "scale so that the scaled sum is approximately 1.0.", + 'helpful') + if prior is not None: + assert prior >= 0, \ + "The index of the prior diagram is negative." + assert min(connect) >= 0, \ + "At least one of the connection indices is negative." + assert prior < len(self.diagrams), \ + "The index of the prior diagram is " + str(prior) \ + + " but there are only " + str(len(self.diagrams)) \ + + " other diagrams.\nThe index is zero-based." + assert connect[0] < len(self.diagrams[prior].flows), \ + "The connection index to the source diagram is " \ + + str(connect[0]) + " but that diagram has only " \ + + str(len(self.diagrams[prior].flows)) \ + + " flows.\nThe index is zero-based." + # Without namedtuple: + #assert connect[0] < len(self.diagrams[prior][1]), \ + # "The connection index to the source diagram is " \ + # + str(connect[0]) + " but that diagram has only " \ + # + len(self.diagrams[prior][1]) \ + # + " flows.\nThe index is zero-based." + assert connect[1] < n, \ + "The connection index to this diagram is " \ + + str(connect[1]) + " but this diagram has only " \ + + str(n) + " flows.\nThe index is zero-based." + assert self.diagrams[prior].angles[connect[0]] is not None, \ + "The connection cannot be made. Check that the magnitude " \ + "of flow " + str(connect[0]) + " of diagram " + str(prior) \ + + "is greater than or equal to the specified tolerance." + flow_error = self.diagrams[prior].flows[connect[0]] \ + + flows[connect[1]] + # Without namedtuple: + #assert self.diagrams[prior][2][connect[0]] is not None, \ + # "The connection cannot be made. Check that the magnitude " \ + # "of flow " + str(connect[0]) + " of diagram " + str(prior) \ + # + "is greater than or equal to the specified tolerance." + #flow_error = self.diagrams[prior][1][connect[0]] \ + # + flows[connect[1]] + assert abs(flow_error) < self.tolerance, \ + "The scaled sum of the connected flows is " \ + + str(flow_error) + ", which is not within the tolerance (" \ + + str(self.tolerance) + ")." + + # Determine if the flows are inputs. + are_inputs = [None]*n + for i, flow in enumerate(flows): + if flow >= self.tolerance: + are_inputs[i] = True + elif flow <= -self.tolerance: + are_inputs[i] = False + else: + verbose.report("The magnitude of flow " + str(i) + " (" \ + + str(flow) + ") is below the tolerance (" \ + + str(self.tolerance) + ").\nIt will not be shown, and " \ + + "it cannot be used in a connection.", 'helpful') + + # Determine the angles of the arrows (before rotation). + angles = [None]*n + for i, (orient, is_input) in enumerate(zip(orientations, are_inputs)): + if orient == 1: + if is_input: + angles[i] = DOWN + elif is_input == False: # Be specific since is_input can be None. + angles[i] = UP + elif orient == 0: + if is_input is not None: + angles[i] = RIGHT + else: + assert orient == -1, \ + "The value of orientations[" + str(i) + "] is " \ + + str(orient) + ", but it must be -1, 0, or 1." + if is_input: + angles[i] = UP + elif is_input == False: + angles[i] = DOWN + + # Justify the lengths of the paths. + if iterable(pathlengths): + assert len(pathlengths) == n, \ + "If pathlengths is a list, then pathlengths and flows must " \ + "have the same length.\npathlengths has length " \ + + str(len(pathlengths)) + ", but flows has length " + str(n) + "." + else: # Make pathlengths into a list. + urlength = pathlengths + ullength = pathlengths + lrlength = pathlengths + lllength = pathlengths + d = dict(RIGHT=pathlengths) + pathlengths = [d.get(angle, 0) for angle in angles] + # Determine the lengths of the top-side arrows from the middle outwards. + for i, (angle, is_input, flow) \ + in enumerate(zip(angles, are_inputs, scaled_flows)): + if angle == DOWN and is_input: + pathlengths[i] = ullength + ullength += flow + elif angle == UP and not is_input: + pathlengths[i] = urlength + urlength -= flow # Flow is negative for outputs + # Determine the lengths of the bottom-side arrows from the middle outwards. + for i, (angle, is_input, flow) \ + in enumerate(zip(angles, are_inputs, scaled_flows)[::-1]): + if angle == UP and is_input: + pathlengths[n-i-1] = lllength + lllength += flow + elif angle == DOWN and not is_input: + pathlengths[n-i-1] = lrlength + lrlength -= flow + # Determine the lengths of the left-side arrows from the bottom upwards. + has_left_input = False + for i, (angle, is_input, spec) \ + in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))[::-1]): + if angle == RIGHT: + if is_input: + if has_left_input: + pathlengths[n-i-1] = 0 + else: + has_left_input = True + # Determine the lengths of the right-side arrows from the top downwards. + has_right_output = False + for i, (angle, is_input, spec) \ + in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))): + if angle == RIGHT: + if not is_input: + if has_right_output: + pathlengths[i] = 0 + else: + has_right_output = True + + # Begin the subpaths, and smooth the transition if the sum of the flows + # is nonzero. + urpath = [(Path.MOVETO, [(self.gap - trunklength / 2.0), # Upper right + gain / 2.0]), + (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, + gain / 2.0]), + (Path.CURVE4, [(self.gap - trunklength / 2.0) / 8.0, + gain / 2.0]), + (Path.CURVE4, [(trunklength / 2.0 - self.gap) / 8.0, + -loss / 2.0]), + (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, + -loss / 2.0]), + (Path.LINETO, [(trunklength / 2.0 - self.gap), + -loss / 2.0])] + llpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower left + loss / 2.0]), + (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, + loss / 2.0]), + (Path.CURVE4, [(trunklength / 2.0 - self.gap) / 8.0, + loss / 2.0]), + (Path.CURVE4, [(self.gap - trunklength / 2.0) / 8.0, + -gain / 2.0]), + (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, + -gain / 2.0]), + (Path.LINETO, [(self.gap - trunklength / 2.0), + -gain / 2.0])] + lrpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower right + loss / 2.0])] + ulpath = [(Path.LINETO, [self.gap - trunklength / 2.0, # Upper left + gain / 2.0])] + + # Add the subpaths and assign the locations of the tips and labels. + tips = np.zeros((n,2)) + label_locations = np.zeros((n,2)) + # Add the top-side inputs and outputs from the middle outwards. + for i, (angle, is_input, spec) \ + in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))): + if angle == DOWN and is_input: + tips[i,:], label_locations[i,:] = self._add_input(ulpath, angle, *spec) + elif angle == UP and not is_input: + tips[i,:], label_locations[i,:] = self._add_output(urpath, angle, *spec) + # Add the bottom-side inputs and outputs from the middle outwards. + for i, (angle, is_input, spec) \ + in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))[::-1]): + if angle == UP and is_input: + tips[n-i-1,:], label_locations[n-i-1,:] = self._add_input(llpath, angle, *spec) + elif angle == DOWN and not is_input: + tips[n-i-1,:], label_locations[n-i-1,:] = self._add_output(lrpath, angle, *spec) + # Add the left-side inputs from the bottom upwards. + has_left_input = False + for i, (angle, is_input, spec) \ + in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))[::-1]): + if angle == RIGHT and is_input: + if not has_left_input: + # Make sure the lower path extends at least as far as the upper one. + if llpath[-1][1][0] > ulpath[-1][1][0]: + llpath.append((Path.LINETO, [ulpath[-1][1][0], llpath[-1][1][1]])) + has_left_input = True + tips[n-i-1,:], label_locations[n-i-1,:] = self._add_input(llpath, angle, *spec) + # Add the right-side outputs from the top downwards. + has_right_output = False + for i, (angle, is_input, spec) \ + in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))): + if angle == RIGHT and not is_input: + if not has_right_output: + # Make sure the upper path extends at least as far as the lower one. + if urpath[-1][1][0] < lrpath[-1][1][0]: + urpath.append((Path.LINETO, [lrpath[-1][1][0], urpath[-1][1][1]])) + has_right_output = True + tips[i,:], label_locations[i,:] = self._add_output(urpath, angle, *spec) + # Trim any hanging vertices. + if not has_left_input: + ulpath.pop() + llpath.pop() + if not has_right_output: + lrpath.pop() + urpath.pop() + + # Concatenate the subpaths in the correct order (clockwise from top). + path = urpath + self._revert(lrpath) + llpath + self._revert(ulpath) \ + + [(Path.CLOSEPOLY, urpath[0][1])] + + # Create a patch with the Sankey outline. + codes, vertices = zip(*path) + vertices = np.array(vertices) + def _get_angle(a, r): + if a is None: return None + else: return a + r + + if prior is None: + if rotation != 0: # By default, none of this is needed. + angles = [_get_angle(angle, rotation) for angle in angles] + rotate = Affine2D().rotate_deg(rotation*90).transform_point + tips = rotate(tips) + label_locations = rotate(label_locations) + vertices = rotate(vertices) + text = self.ax.text(0, 0, s=patchlabel, ha='center', va='center') + else: + rotation = self.diagrams[prior].angles[connect[0]] - angles[connect[1]] + # Without namedtuple: + #rotation = self.diagrams[prior][2][connect[0]] \ + # - angles[connect[1]] + angles = [_get_angle(angle, rotation) for angle in angles] + rotate = Affine2D().rotate_deg(rotation*90).transform_point + tips = rotate(tips) + offset = self.diagrams[prior].tips[connect[0]] - tips[connect[1]] + # Without namedtuple: + #offset = self.diagrams[prior][3][connect[0]] - tips[connect[1]] + translate = Affine2D().translate(*offset).transform_point + tips = translate(tips) + label_locations = translate(rotate(label_locations)) + vertices = translate(rotate(vertices)) + kwds = dict(s=patchlabel, ha='center', va='center') + text = self.ax.text(*offset, **kwds) + if False: # DEBUG + print "llpath\n", llpath + print "ulpath\n", self._revert(ulpath) + print "urpath\n", urpath + print "lrpath\n", self._revert(lrpath) + xs, ys = zip(*vertices) + self.ax.plot(xs, ys, 'go-') + patch = PathPatch(Path(vertices, codes), + fc=kwargs.pop('fc', kwargs.pop('facecolor', # Custom + '#bfd1d4')), # defaults + lw=kwargs.pop('lw', kwargs.pop('linewidth', + '0.5')), + **kwargs) + self.ax.add_patch(patch) + + # Add the path labels. + for i, (number, angle) in enumerate(zip(flows, angles)): + if labels[i] is None or angle is None: + labels[i] = '' + elif self.unit is not None: + quantity = self.format%abs(number) + self.unit + if labels[i] != '': + labels[i] += "\n" + labels[i] += quantity + texts = [] + for i, (label, location) in enumerate(zip(labels, label_locations)): + if label: s = label + else: s = '' + texts.append(self.ax.text(x=location[0], y=location[1], + s=s, + ha='center', va='center')) + # Text objects are placed even they are empty (as long as the magnitude + # of the corresponding flow is larger than the tolerance) in case the + # user wants to provide labels later. + + # Expand the size of the diagram if necessary. + self.extent = (min(np.min(vertices[:,0]), np.min(label_locations[:,0]), self.extent[0]), + max(np.max(vertices[:,0]), np.max(label_locations[:,0]), self.extent[1]), + min(np.min(vertices[:,1]), np.min(label_locations[:,1]), self.extent[2]), + max(np.max(vertices[:,1]), np.max(label_locations[:,1]), self.extent[3])) + # Include both vertices _and_ label locations in the extents; there are + # where either could determine the margins (e.g., arrow shoulders). + + # Add this diagram as a subdiagram. + self.diagrams.append(Bunch(patch=patch, flows=flows, angles=angles, + tips=tips, text=text, texts=texts)) + # Without namedtuple: + #self.diagrams.append((patch, flows, angles, tips, text, texts)) + + # Allow a daisy-chained call structure (see docstring for the class). + return self + + def finish(self): + """Adjust the axes and return a list of information about the + subdiagram(s). + + Each entry in the subdiagram list is a namedtuple with the following + fields: + patch: Sankey outline (an instance of maplotlib.patches.PathPatch) + flows: Values of the flows (positive for input, negative for output) + angles: List of angles of the arrows [deg/90] + For example, if the diagram has not been rotated, an input to + the top side will have an angle of 3 (DOWN), and an output from + the top side will have an angle of 1 (UP). If a flow has been + skipped (because it is too close to 0), then its angle will be + None. + tips: Array where each row is an [x, y] pair indicating the positions + of the tips (or "dips") of the flow paths + If the magnitude of a flow is less the tolerance for the Sankey + class, the flow is skipped and its tip will be at the center of + the diagram. + text: matplotlib.text.Text instance for the label of the diagram + texts: List of matplotlib.text.Text instances for the labels of flows + """ + self.ax.axis([self.extent[0] - self.margin, + self.extent[1] + self.margin, + self.extent[2] - self.margin, + self.extent[3] + self.margin]) + self.ax.set_aspect('equal', adjustable='datalim') + return self.diagrams + + def __init__(self, ax=None, scale=1.0, unit='', format='%G', gap=0.25, + radius=0.1, shoulder=0.03, offset=0.15, head_angle=100, + margin=0.4, tolerance=1e-6, **kwargs): + """Create a new Sankey diagram. + + ax: Axes onto which the data should be plotted + If not provided, they will be created. + scale: Scaling factor for the flows + This factor sizes the width of the paths in order to + maintain proper layout. The same scale is applied to all + subdiagrams. The value should be chosen such that the + product of the scale and the sum of the inputs is + approximately 1 (and the product of the scale and the sum + of the outputs is approximately -1). + unit: Unit associated with the flow quantities + If unit is None, then none of the quantities are labeled. + format: A Python number formatting string to be used in labeling + the flow as a quantity (i.e., a number times a unit, where + the unit is given) + gap: Space between paths in that break in/break away to/from + the top or bottom + radius: Inner radius of the vertical paths + shoulder: Output arrow shoulder + offset: Text offset (away from the dip or tip of the arrow) + head_angle: Angle of the arrow heads (and negative of the angle of the + tails) [deg] + margin: Minimum space between Sankey outlines and the edge of the + plot area + tolerance: Acceptable maximum of the magnitude of the sum of flows + The magnitude of the sum of connected flows cannot be + greater than this value. If the magnitude of the sum of + the flows of a subdiagram is greater than this value, a + warning is displayed. + **kwargs: Propagated to Sankey.add() + + The above arguments are applied to all subdiagrams so that there is + consistent alignment and formatting. + + If this class is instantiated with any keyworded arguments (**kwargs) + other than those explicitly listed above, they will be passed to the + add() method, which will create the first subdiagram. + + In order to draw a complex Sankey diagram, create an instance of this + class by calling it without any **kwargs: + sankey = Sankey() + Then add simple Sankey sub-diagrams: + sankey.add() # 1 + sankey.add() # 2 + #... + sankey.add() # n + Finally, create the full diagram: + sankey.finish() + Or, instead, simply daisy-chain those calls: + Sankey().add().add... .add().finish() + """ + # Check the arguments. + assert gap >= 0, \ + "The gap is negative.\n" \ + + "This isn't allowed because it would cause the paths to overlap." + assert radius <= gap, \ + "The inner radius is greater than the path spacing.\n" \ + + "This isn't allowed because it would cause the paths to overlap." + assert head_angle >= 0, \ + "The angle is negative.\n" \ + + "This isn't allowed because it would cause inputs to look "\ + + "like outputs and vice versa." + assert tolerance >= 0, \ + "The tolerance is negative.\nIt must be a magnitude." + + # Create axes if necessary. + if ax is None: + import matplotlib.pyplot as plt + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[]) + + self.diagrams = [] + + # Store the inputs. + self.ax = ax + self.unit = unit + self.format = format + self.scale = scale + self.gap = gap + self.radius = radius + self.shoulder = shoulder + self.offset = offset + self.margin = margin + self.pitch = np.tan(np.pi * (1 - head_angle / 180.0) / 2.0) + self.tolerance = tolerance + + # Initialize the vertices of tight box around the diagram(s). + self.extent = np.array((np.inf, -np.inf, np.inf, -np.inf)) + + # If there are any kwargs, create the first subdiagram. + if len(kwargs): + self.add(**kwargs) + +if __name__ == '__main__': + """Demonstrate the Sankey class. + """ + import matplotlib.pyplot as plt + from itertools import cycle + + # Example 1 -- Mostly defaults + # This demonstrates how to create a simple diagram by implicitly calling the + # Sankey.add() method and by appending finish() to the call to the class. + Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], + labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], + orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() + plt.title("The default settings produce a diagram like this.") + # Notice: + # 1. Axes weren't provided when Sankey() was instantiated, so they were + # created automatically. + # 2. The scale argument wasn't necessary since the data was already + # normalized. + # 3. By default, the lengths of the paths are justified. + + # Example 2 + # This demonstrates: + # 1. Setting one path longer than the others + # 2. Placing a label in the middle of the diagram + # 3. Using the the scale argument to normalize the flows + # 4. Implicitly passing keyword arguments to PathPatch() + # 5. Changing the angle of the arrow heads + # 6. Changing the offset between the tips of the paths and their labels + # 7. Formatting the numbers in the path labels and the associated unit + # 8. Changing the appearance of the patch and the labels after the figure + # is created + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Flow Diagram of a Widget") + sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, + format='%.0f', unit='%') + sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], + labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', + 'Fifth', 'Hurray!'], + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], + pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, + 0.25], + patchlabel="Widget\nA", + alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() + diagrams = sankey.finish() + diagrams[0].patch.set_facecolor('#37c959') + diagrams[0].texts[-1].set_color('r') + diagrams[0].text.set_fontweight('bold') + # Without namedtuple: + #diagrams[0][0].set_facecolor('#37c959') + #diagrams[0][5][-1].set_color('r') + #diagrams[0][4].set_fontweight('bold') + # Notice: + # 1. Since the sum of the flows isn't zero, the width of the trunk isn't + # uniform. A message is given in the terminal window. + # 2. The second flow doesn't appear because its value is zero. A messsage + # is given in the terminal window. + + # Example 3 + # This demonstrates: + # 1. Connecting two systems + # 2. Turning off the labels of the quantities + # 3. Adding a legend + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") + flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] + sankey = Sankey(ax=ax, unit=None) + sankey.add(flows=flows, label='one', + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) + sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', + orientations=[-1, -1, -1], prior=0, connect=(0, 0)) + diagrams = sankey.finish() + diagrams[-1].patch.set_hatch('/') + # Without namedtuple: + #diagrams[-1][0].set_hatch('/') + + plt.legend(loc='best') + # Notice that only one connection is specified, but the systems form a + # circuit since: (1) the lengths of the paths are justified and (2) the + # orientation and ordering of the flows is mirrored. + + # Example 4 + # This tests a long chain of connections. + links_per_side = 6 + def side(sankey, n=1): + prior = len(sankey.diagrams) + colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) + for i in range(0, 2*n, 2): + sankey.add(flows=[1, -1], orientations=[-1, -1], + patchlabel=str(prior+i), facecolor=colors.next(), + prior=prior+i-1, connect=(1, 0), alpha=0.5) + sankey.add(flows=[1, -1], orientations=[1, 1], + patchlabel=str(prior+i+1), facecolor=colors.next(), + prior=prior+i, connect=(1, 0), alpha=0.5) + def corner(sankey): + prior = len(sankey.diagrams) + sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel=str(prior), facecolor='k', + prior=prior-1, connect=(1, 0), alpha=0.5) + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Why would you want to do this?" \ + "\n(But you could.)") + sankey = Sankey(ax=ax, unit=None) + sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel="0", facecolor='k', + rotation=45) + side(sankey, n=links_per_side) + corner(sankey) + side(sankey, n=links_per_side) + corner(sankey) + side(sankey, n=links_per_side) + corner(sankey) + side(sankey, n=links_per_side) + sankey.finish() + # Notice: + # 1. The alignment doesn't drift significantly (if at all; with 16007 + # subdiagrams there is still closure). + # 2. The first diagram is rotated 45 degrees, so all other diagrams are + # rotated accordingly. + + # Example 5 + # This demonstrates a practical example -- a Rankine power cycle. + fig = plt.figure(figsize=(8, 12)) + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" + + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") + Hdot = np.array([260.431, 35.078, 180.794, 221.115, 22.700, + 142.361, 10.193, 10.210, 43.670, 44.312, + 68.631, 10.758, 10.758, 0.017, 0.642, + 232.121, 44.559, 100.613, 132.168])*1.0e6 # W + sankey = Sankey(ax=ax, format='%.3G', unit='W', gap=0.5, scale=1.0/Hdot[0]) + # Shared copy: + #Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, + # 142.361, 10.193, 10.210, 43.670, 44.312, + # 68.631, 10.758, 10.758, 0.017, 0.642, + # 232.121, 44.559, 100.613, 132.168] # MW + #sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) + sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', + flows=[Hdot[13], Hdot[6], -Hdot[7]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.883, 0.25], + orientations=[1, -1, 0]) + sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', + flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], + labels=[None, '', None, None], + pathlengths=[0.25, 0.25, 1.93, 0.25], + orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) + sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', + flows=[Hdot[14], Hdot[8], -Hdot[9]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.25, 0.25], + orientations=[1, 0, 0], prior=1, connect=(3, 1)) + sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', + flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], + pathlengths=[0.25, 1.543, 0.25, 0.25], + labels=['', '', None, None], + orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) + sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, + flows=[Hdot[11], -Hdot[12]], + labels=['\n', None], + pathlengths=[1.0, 1.01], + orientations=[1, 1], prior=3, connect=(2, 0)) + sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', + flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], + labels=['Heat rate', '', '', None, None], + pathlengths=0.25, + orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) + sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', + flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], + labels=['', None, None, None], + pathlengths=[0.25, 0.153, 1.543, 0.25], + orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) + sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', + flows=[Hdot[2], -Hdot[2]], + labels=[None, None], + pathlengths=[0.725, 0.25], + orientations=[-1, 0], prior=6, connect=(3, 0)) + sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', + flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], + labels=[None, 'Shaft power', None, '', 'Shaft power'], + pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], + orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) + sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, + flows=[Hdot[5], -Hdot[18], -Hdot[6]], + labels=['', 'Heat rate', None], + pathlengths=[0.45, 0.25, 0.883], + orientations=[-1, 1, 0], prior=8, connect=(2, 0)) + diagrams = sankey.finish() + for diagram in diagrams: + diagram.text.set_fontweight('bold') + diagram.text.set_fontsize('10') + for text in diagram.texts: + # Without namedtuple: + #diagram[4].set_fontweight('bold') + #diagram[4].set_fontsize('10') + #for text in diagram[5]: + text.set_fontsize('10') + # Notice that the explicit connections are handled automatically, but the + # implicit ones currently are not. The lengths of the paths and the trunks + # must be adjusted manually, and that is a bit tricky. + + plt.show() + From 2dc70020dc8a9b69e5b280e356ce3a4d4c5332c0 Mon Sep 17 00:00:00 2001 From: Pim Schellart Date: Tue, 13 Sep 2011 13:58:13 +0200 Subject: [PATCH 132/214] Added cubehelix monotonically increasing colorscheme (developed by D.A. Green) to matplotlib colorscheme list. --- lib/matplotlib/_cm.py | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index 5bea5199cf4b..fb54e35cc86a 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -46,6 +46,57 @@ 'blue': lambda x: -1.1 * np.sin((x * 20.9) * np.pi), } +def cubehelix(gamma = 1.0, s = 0.5, r = -1.5, h = 1.0): + """Return dictionary of (r,g,b) conversion functions for the cubehelix + color scheme. + + Unlike most other color schemes cubehelix was designed by D.A. Green to + be monotonically increasing in terms of perceived brightness. + Also, when printed on a black and white postscript printer, the scheme + results in a greyscale with monotonically increasing brightness. + + Optional keyword arguments: + + ========= ======================================================= + Keyword Description + ========= ======================================================= + gamma gamma factor to emphasise either low intensity values + (gamma < 1), or high intensity values (gamma > 1); + defaults to 1.0. + s the start color; defaults to 0.5. + r the number of r,g,b rotations in color that are made + from the start to the end of the color scheme; defaults + to -1.5. + h the hue parameter which controls how saturated the + colors are. If this parameter is zero then the color + scheme is purely a greyscale. + ========= ======================================================= + + """ + + def get_color_function(p0, p1): + def color(x): + # Apply gamma factor to emphasise low or high intensity values + xg = x**gamma + + # Calculate amplitude and angle of deviation from the black + # to white diagonal in the plane of constant + # perceived intensity. + a = h * xg * (1 - xg) / 2 + + phi = 2 * np.pi * (s / 3 + r * x) + + return xg + a * (p0 * np.cos(phi) + p1 * np.sin(phi)) + return color + + return { + 'red': get_color_function(-0.14861, 1.78277), + 'green': get_color_function(-0.29227, -0.90649), + 'blue': get_color_function(1.97294, 0.0), + } + +_cubehelix_data = cubehelix() + _bwr_data = ((0.0, 0.0, 1.0), (1.0, 1.0, 1.0), (1.0, 0.0, 0.0)) _brg_data = ((0.0, 0.0, 1.0), (1.0, 0.0, 0.0), (0.0, 1.0, 0.0)) @@ -1575,6 +1626,7 @@ def gfunc32(x): 'brg': _brg_data, 'cool': _cool_data, 'copper': _copper_data, + 'cubehelix': _cubehelix_data, 'flag': _flag_data, 'gnuplot': _gnuplot_data, 'gnuplot2': _gnuplot2_data, From 27831c3eb928b319e5f076b175cba081a885ec04 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 13 Sep 2011 14:34:37 -0400 Subject: [PATCH 133/214] Add ?, ! and & symbols to mathtext. Closes #466. --- lib/matplotlib/_mathtext_data.py | 5 +- lib/matplotlib/mathtext.py | 2 +- .../test_mathtext/mathtext_cm_65.pdf | Bin 0 -> 4579 bytes .../test_mathtext/mathtext_cm_65.png | Bin 0 -> 1246 bytes .../test_mathtext/mathtext_cm_65.svg | 165 ++++++++++++++++++ .../test_mathtext/mathtext_stix_65.pdf | Bin 0 -> 4386 bytes .../test_mathtext/mathtext_stix_65.png | Bin 0 -> 1267 bytes .../test_mathtext/mathtext_stix_65.svg | 136 +++++++++++++++ .../test_mathtext/mathtext_stixsans_65.pdf | Bin 0 -> 4387 bytes .../test_mathtext/mathtext_stixsans_65.png | Bin 0 -> 1267 bytes .../test_mathtext/mathtext_stixsans_65.svg | 136 +++++++++++++++ lib/matplotlib/tests/test_mathtext.py | 3 +- 12 files changed, 444 insertions(+), 3 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index fd1ece2b7da7..b324ff0dd82c 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -108,7 +108,7 @@ r'7' : ('cmr10', 127), r'8' : ('cmr10', 77), r'9' : ('cmr10', 22), - r' :' : ('cmr10', 85), + r':' : ('cmr10', 85), r';' : ('cmr10', 31), r'=' : ('cmr10', 41), r'\leftbracket' : ('cmr10', 62), @@ -243,6 +243,9 @@ r'\rightarrow' : ('cmsy10', 12), r'\to' : ('cmsy10', 12), r'\spadesuit' : ('cmsy10', 7), + r'?' : ('cmr10', 50), + r'!' : ('cmr10', 29), + r'&' : ('cmr10', 109) } latex_to_cmex = { diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 517ca9b74a25..f9dd615d8e41 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -2178,7 +2178,7 @@ def __init__(self): ).setParseAction(self.customspace).setName('customspace') unicode_range = u"\U00000080-\U0001ffff" - symbol =(Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!'@()\[\]|%s])|(\\[%%${}\[\]_|])" % unicode_range) + symbol =(Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" % unicode_range) | (Combine( bslash + oneOf(tex2uni.keys()) diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8c5725eb9a9858836027838aeb538abe2da9f869 GIT binary patch literal 4579 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 B(lY=6 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png new file mode 100644 index 0000000000000000000000000000000000000000..c9ed541dcb26f18033dfdcccd87ff8cea806ac0d GIT binary patch literal 1246 zcmeAS@N?(olHy`uVBq!ia0y~yVB!U`y*b!`@Ci zycd|Tnwq#fJ6}l~V3*RuNBc=SgBsDw4W_-`KmkmQ1?vTlSH9%&*#?^G@EL z{<}iw)JLxO=S$|#DYl!MwKa;D;lTckRo@vH4%9biFfep=urVy?7%;}4(D#fDQ$K!w zem-V@o$dYo_2>WmsoAxAck!1O7gbK4oo#MxVlt(jUw+x*#fzW)m$R*!QvLm1>fttC zNf{ZR=;&zMW98Gr{28D z@ijSf{`~VB8Cc<$Ly^t{h2>`^5mPFQo9ox*pz`5m6Vh$*}Hdd+S;vKO?Q{S zUl%DYBXee5?CwojS6A`y@;<$?GPv^dGv8^`rp0u%u!XJ+TYa^PpYcy*+`gKbYooWP z)zsM3*4BDXYHV!WQ}@>jm?F*{Y-Z2CcZ5Nzc`jRq!u@@o_g{7=G@+% zpANLwvha~hT3XsBp!=(AxB}Sw)Enx*yt}*Gruv)C-Me>h?krB9HGB5tKUJ%fii(VG yZ_7Qs%y;%H8`TX#F3b!8N9GP_{)6ZKKfGUh*pe>u` + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6ae0be35c0a3c965ee1380b7a98a576d0759c514 GIT binary patch literal 4386 zcmb^#2~<;8_MlebTU<_E#wz3UXtXNu_k<`i0wG9Q#KZ*)E}!HFQnJwGrv?*5r4w;9!7H%t+?}9?l7z$(jQ2crJyv0}3K&Ku8G2Tl5Gq z$b%qZeDb@zP5=rK2NDPZZ?gavePVdL&8pM#0!W0cRBFhccM1THGDEgu?m65&M}cVo zk8lc+T7eUIz_=J_Q#rlSk^ + + + + + + + + + + + + + + + + + + + + + + rVKr$d4V(=Eh4wNnmmqEx5fNOZW z)nU^?i;x8xWS$M;y6nU7SYB`B!mLiHE#gQkf&j}vt=c3Zo{}K7(F838xY`8ORq;Bj z9!iMeEh$1OAdyQ&kJ$wq&zUjj2H8@w+cDzxh*`y#_LfjR1}MyVK0ZDp9O0F|V*|F` z_^P(4c}?7zhqE6h94C(HK1?3mWkTG@`odFIzHiWt6)R)>)t}Q%%LiN;Runw4d&uzW z-`=@8`CLZ9o`-d%2d~~Mk>^LPYx3c9Pw(qvUy@Z@ojtUs6tgS;KGQJ&Y2b=U7nTM` z{BgWy@C_6~w@&V0in=1BNLnEUm_+XWGltTv61k_$7^BK;D!3>1WdT z+C$Hb-7eh!szd*zUa$2W6n*p54{Oh^s+VQoCyVxl{V~Qc``{60WK67olBsDx_cdoO zkCgeJs2Otluj}=17kb?1V=$$fZn)2>s&8|MxgJUTD>+gL`ip)So4yKpVuP}V)I%<${^o^!u0;keRw zbRYTmUnx)ia=_J;DL=~NZxl9kIr+);_uoJDvoUnrg9n3h4(9l0PCw!MfjRf;!J@bV?>jXR~2U~j2DarHdcx}wq%(tIq-UPl%jCAyZ+FZAE|P&am@dNtO+vA$Y;EbR8K9x;jMyla!13-5ir zwyuB4q4eb6bk*PclgBU5w_@hPak7)2ZaLoX`&9>O=j9b!_cjKm zQ58LBZC|mWD7rYaGqr!Q_DYRoS=EF7@m+6zuN*z3(OLPI^OfKHTG_j~_VrB7jLXd( zLncRl@)B=&zE7{Zrfd-XoHt_gqb)hJAIZOW=H$O>uT27Wi{QlG8% z+fSZMytdqiH^;8l2`zIj{X@oXGsi9Mx8;1shgtbGnN=|>i>c`?>f64xv6`*U#Az3M zT|cs@3@S`&tKCq06xVzjIczD8D-_2b^RUZ_2&+~rm>g=`7MsKs-ug4JOl^?!| zK6vg@dbc2uZ5p)r#I1{Kqhbi&+H2JYc7WqV=sL^xu?yB~XZE~wGqf!8Ou2H&rwOT> zeqVFnt2chr8DDpFXim4F$Z55z8w<%UbH@0zQL2W@@G_0x?lo`DKkawFlcNG? z>K_1X>uNmiakXFH;-QrnwWg!}99hS@#`rmwB+Y2vcJuLqz6H56{)p7Scm7b9ehZA> z{v60m>9AZ|%*qag{C+vpcg~SrArTkm7KE=Zr4}FlX>p}bvAQKcF-f+1yq_jt#>qOY zaZqDE%e7o=)D%Wl_76(?ZeYVT^`fWthb>{pHVd_bGqyfmhhx8g z@o(+U>?W@ zr82<9QEjx@1%v_!moj0l92uZg5FmhIXh0DJ0Z4+P!88nyu)tJ^QZ_0lR7Qh=hdCDI z+(bY_S-ewc;>>^!0yt+*=WTY*q6c!g@t%XX3r4F2l>x4#EpftNhQVVvw-OY~dSqnL zf0A#JUr{~}U?7g@w^ykO-7WCu$Qa^@o;L`^2pNNBGlIXUJNia8Am2!Pa29Pu_%zfD?Mr(|wzNjP8R$=Vjl`K{NYRIAANf+$ zgJv*0c>`5!Fd-w7&ct&I`s}6Y|h>?b3(ewDwvGPAYE?& z$($|?wmlF3;h|jpA}zcu?O?D&Z3k1pfIUx35c2jg=(l!w6nyJn zq-CjgI#Y}sRw2*JpeVMT&ZLrPCxd2RCWC1wgHXcv@&y?r#k7Ob3V2yt@dO)ZH1Rg^ tpBYgWgB6G;2=@9Ks}&tQvG3O!GkF+1SMkr;1Tmbnl2BkWS;TlX_8);pZD9Za literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png new file mode 100644 index 0000000000000000000000000000000000000000..1499121e10cc093cd054b6f2d9f6b064e40722fc GIT binary patch literal 1267 zcmeAS@N?(olHy`uVBq!ia0y~yVB!U`y*b!`DZ9F~>hWn_bv??paDktmQj;v%nT3g*JOWZU^wu=QU@D@LgxT7UMQ?yz1q;& zSorhj&w;D2&N>&WHMQdFtE;nYuV$Ib*;a`>Evh^#w_tMz+Y5p7^K83czI=IObGrYY znx96Sbh^L4zi)nSzD=c3pPcQjE$Nw=n%na4%gr{+?V4|2f9zm0d$f(|2XjH*3yONN zyF`+clMPKwMAFaA>8!DnpROODH|PJ~-{ou8tTB13In~S1%1UZ?`TM@w-`|cN@0WiJ z#B1ebe|Q6}R_K?v&#Sq&t2EoD{@5f9dX_TSCU5cL@7fZp?4qja^VddXOqt=Tv&HS){1Z)R^LrKP*O#r2Qf-CdrX zmZr8YcDGpmy*-^vmoDw-c=7smx2$#9mS=1Y+k|;9G|scDmHJs@cW$2T?FeZ(xjtTL zGn3fq=btZ*TYvn@l@J{r9hdz4{5`e5&D7M?l2TGs*2V9?_v&J!*{2F7s|#=5lvI zrV|Km?5Qlac4NP_;`g1M#m{fqvRtsz*4F;``ucj)`$8eBuL2!nXkj7o`}_O;%gg=U zH%9ct=!r*f%juLh&vV%t)%)}3&m9F1ok~hex4z_SDEkQXf{(wyzl=pe!r5OhUSzzv zv(p$Dm^Ht?tbBQAqOyAu(7}e5mXePjKW<{Qnv&7LSN!|i+Zl7`#%`|r|L^aP;^%%M zT&)rk5*^Xo^GyFuet3GiKF9&i&d!C8j&y2F_1d^+k4$lKG0+b;UPUw90_Tz2Aa@^4 zGTfGX``Q<-G?ybkepJ-_|7RPwr$R7%eO&L#l`A9S;`)*{O8ou%xA5tysUQmuxAPyr zb0_A@moGN`ZAb>B;h1eRJ1p00i_>zopr E0FnqK4gdfE literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg new file mode 100644 index 000000000000..72c366c49cb0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg @@ -0,0 +1,136 @@ + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c97ed107b47b63dab50070c706db4e94d87dd75b GIT binary patch literal 4387 zcmb_g3sh9q8eXU=3}Ly_%9QJN5%oS;$%6B4ONyy-mHSS=y|4y + + + + + + + + + + + + + + + + + + + + + + paG$w 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 E0FnqK4gdfE literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg new file mode 100644 index 000000000000..9cda8666a019 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg @@ -0,0 +1,136 @@ + + + + diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 7d6c0668fa85..84973ed289a8 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -83,7 +83,8 @@ r'${x}_{{y}_{b}^{a}}^{{z}_{c}^{d}}$', r'${y}_{3}^{\prime \prime \prime }$', r"$\left( \xi \left( 1 - \xi \right) \right)$", # Bug 2969451 - r"$\left(2 \, a=b\right)$" # Sage bug #8125 + r"$\left(2 \, a=b\right)$", # Sage bug #8125 + r"$? ! &$", # github issue #466 ] digits = "0123456789" From 7a7d7ac11e6b9932855513d1cef8ed69865ddfea Mon Sep 17 00:00:00 2001 From: Evan Davey + + + + + + + + + + + + + + + + + + + + + + Date: Thu, 15 Sep 2011 14:49:06 +0200 Subject: [PATCH 134/214] Allows the g flag to be set so that dividend data can be downloaded (g=v). It appears only 'd' and 'v' are valid options so perhaps an additional error check may also be warranted. --- lib/matplotlib/finance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index aa1a951a200e..d255ba5f59dc 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -132,7 +132,7 @@ def parse_yahoo_historical(fh, adjusted=True, asobject=False): return d.view(np.recarray) # Close enough to former Bunch return -def fetch_historical_yahoo(ticker, date1, date2, cachename=None): +def fetch_historical_yahoo(ticker, date1, date2, cachename=None,g='d'): """ Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. @@ -160,11 +160,11 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None): d2 = (date2.month-1, date2.day, date2.year) - urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=d&ignore=.csv' + urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv' url = urlFmt % (d1[0], d1[1], d1[2], - d2[0], d2[1], d2[2], ticker) + d2[0], d2[1], d2[2], ticker, g) if cachename is None: From 51f461e74292521703c115ed5f1783da6d6d042a Mon Sep 17 00:00:00 2001 From: Evan Davey Date: Thu, 15 Sep 2011 16:18:49 +0200 Subject: [PATCH 135/214] Makes fetch_historical_yahoo dividend option more user friendly --- lib/matplotlib/finance.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index d255ba5f59dc..08b8f9a7b9c3 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -132,7 +132,7 @@ def parse_yahoo_historical(fh, adjusted=True, asobject=False): return d.view(np.recarray) # Close enough to former Bunch return -def fetch_historical_yahoo(ticker, date1, date2, cachename=None,g='d'): +def fetch_historical_yahoo(ticker, date1, date2, cachename=None,dividends=False): """ Fetch historical data for ticker between date1 and date2. date1 and date2 are date or datetime instances, or (year, month, day) sequences. @@ -143,6 +143,9 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None,g='d'): cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) + + set dividends=True to return dividends instead of price data. With + this option set, parse functions will not work a file handle is returned """ @@ -160,6 +163,12 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None,g='d'): d2 = (date2.month-1, date2.day, date2.year) + if dividends: + g='v' + verbose.report('Retrieving dividends instead of prices') + else: + g='d' + urlFmt = 'http://table.finance.yahoo.com/table.csv?a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv' From dd19aab4d157415d4d64aa119a4b4cda49b9c8e4 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Fri, 16 Sep 2011 18:29:18 +0900 Subject: [PATCH 136/214] fix a bug an DraggableAnnotate reported by Daniel Hyams --- lib/matplotlib/offsetbox.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 9bdf5bf4b975..52ed7d629a15 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1533,6 +1533,7 @@ def save_offset(self): self.ox, self.oy = ox0, oy0 self.annotation.textcoords = "figure pixels" + self.update_offset(0, 0) def update_offset(self, dx, dy): ann = self.annotation From 87321b7aec7c1ea104cd75290d6f0963359e611a Mon Sep 17 00:00:00 2001 From: Pim Schellart Date: Fri, 16 Sep 2011 14:54:36 +0200 Subject: [PATCH 137/214] Updates to cubehelix color scheme. Expanded docstring of cubehelix color scheme generation function, fixed function definition to comply with PEP8 and added cubehelix to cm namespace so users can create a custom variation of cubehelix for use in register_cmap. --- lib/matplotlib/_cm.py | 23 +++++++++++++++++------ lib/matplotlib/cm.py | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index fb54e35cc86a..ceeff9c644bd 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -46,14 +46,25 @@ 'blue': lambda x: -1.1 * np.sin((x * 20.9) * np.pi), } -def cubehelix(gamma = 1.0, s = 0.5, r = -1.5, h = 1.0): - """Return dictionary of (r,g,b) conversion functions for the cubehelix - color scheme. +def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0): + """Return custom data dictionary of (r,g,b) conversion functions, which + can be used with :func:`register_cmap`, for the cubehelix color scheme. Unlike most other color schemes cubehelix was designed by D.A. Green to be monotonically increasing in terms of perceived brightness. Also, when printed on a black and white postscript printer, the scheme results in a greyscale with monotonically increasing brightness. + This color scheme is named cubehelix because the r,g,b values produced + can be visualised as a squashed helix around the diagonal in the + r,g,b color cube. + + For a unit color cube (i.e. 3-D coordinates for r,g,b each in the + range 0 to 1) the color scheme starts at (r,g,b) = (0,0,0), i.e. black, + and finishes at (r,g,b) = (1,1,1), i.e. white. For some fraction *x*, + between 0 and 1, the color is the corresponding grey value at that + fraction along the black to white diagonal (x,x,x) plus a color + element. This color element is calculated in a plane of constant + perceived intensity and controlled by the following parameters. Optional keyword arguments: @@ -63,13 +74,13 @@ def cubehelix(gamma = 1.0, s = 0.5, r = -1.5, h = 1.0): gamma gamma factor to emphasise either low intensity values (gamma < 1), or high intensity values (gamma > 1); defaults to 1.0. - s the start color; defaults to 0.5. + s the start color; defaults to 0.5 (i.e. purple). r the number of r,g,b rotations in color that are made from the start to the end of the color scheme; defaults - to -1.5. + to -1.5 (i.e. -> B -> G -> R -> B). h the hue parameter which controls how saturated the colors are. If this parameter is zero then the color - scheme is purely a greyscale. + scheme is purely a greyscale; defaults to 1.0. ========= ======================================================= """ diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 9621d345bfb4..87386138954d 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -13,6 +13,7 @@ import matplotlib.colors as colors import matplotlib.cbook as cbook from matplotlib._cm import datad +from matplotlib._cm import cubehelix cmap_d = dict() From dec14bd8a28cbc9ef4f952dafe8261da314f452e Mon Sep 17 00:00:00 2001 From: Kevin Davies Date: Fri, 16 Sep 2011 21:34:28 -0400 Subject: [PATCH 138/214] Improved documentation and formatting of Sankey class and its demo --- doc/api/api_changes.rst | 2 + examples/api/sankey_demo.py | 63 +-- lib/matplotlib/sankey.py | 788 ++++++++++++++---------------------- 3 files changed, 338 insertions(+), 515 deletions(-) diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index 4bcace995e7a..a1f6682170fc 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -14,6 +14,8 @@ For new features that were added to matplotlib, please see Changes in 1.1.x ================ +* Added new :class:`matplotlib.sankey.Sankey` for generating Sankey diagrams. + * In :meth:`~matplotlib.pyplot.imshow`, setting *interpolation* to 'nearest' will now always mean that the nearest-neighbor interpolation is performed. If you want the no-op interpolation to be performed, choose 'none'. diff --git a/examples/api/sankey_demo.py b/examples/api/sankey_demo.py index 5845cb37f1e7..7fa5d33dfa41 100644 --- a/examples/api/sankey_demo.py +++ b/examples/api/sankey_demo.py @@ -6,12 +6,6 @@ from matplotlib.sankey import Sankey from itertools import cycle - -"""Demonstrate the Sankey class. -""" -import matplotlib.pyplot as plt -from itertools import cycle - # Example 1 -- Mostly defaults # This demonstrates how to create a simple diagram by implicitly calling the # Sankey.add() method and by appending finish() to the call to the class. @@ -35,8 +29,8 @@ # 5. Changing the angle of the arrow heads # 6. Changing the offset between the tips of the paths and their labels # 7. Formatting the numbers in the path labels and the associated unit -# 8. Changing the appearance of the patch and the labels after the figure -# is created +# 8. Changing the appearance of the patch and the labels after the figure is +# created fig = plt.figure() ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Flow Diagram of a Widget") @@ -49,20 +43,17 @@ pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, 0.25], patchlabel="Widget\nA", - alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() + alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() diagrams = sankey.finish() diagrams[0].patch.set_facecolor('#37c959') diagrams[0].texts[-1].set_color('r') diagrams[0].text.set_fontweight('bold') -# Without namedtuple: -#diagrams[0][0].set_facecolor('#37c959') -#diagrams[0][5][-1].set_color('r') -#diagrams[0][4].set_fontweight('bold') # Notice: -# 1. Since the sum of the flows isn't zero, the width of the trunk isn't -# uniform. A message is given in the terminal window. -# 2. The second flow doesn't appear because its value is zero. A messsage -# is given in the terminal window. +# 1. Since the sum of the flows is nonzero, the width of the trunk isn't +# uniform. If verbose.level is helpful (in matplotlibrc), a message is +# given in the terminal window. +# 2. The second flow doesn't appear because its value is zero. Again, if +# verbose.level is helpful, a message is given in the terminal window. # Example 3 # This demonstrates: @@ -79,18 +70,17 @@ orientations=[-1, -1, -1], prior=0, connect=(0, 0)) diagrams = sankey.finish() diagrams[-1].patch.set_hatch('/') -# Without namedtuple: -#diagrams[-1][0].set_hatch('/') - plt.legend(loc='best') -# Notice that only one connection is specified, but the systems form a -# circuit since: (1) the lengths of the paths are justified and (2) the -# orientation and ordering of the flows is mirrored. +# Notice that only one connection is specified, but the systems form a circuit +# since: (1) the lengths of the paths are justified and (2) the orientation and +# ordering of the flows is mirrored. # Example 4 # This tests a long chain of connections. links_per_side = 6 def side(sankey, n=1): + """Generate a side chain. + """ prior = len(sankey.diagrams) colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) for i in range(0, 2*n, 2): @@ -101,14 +91,15 @@ def side(sankey, n=1): patchlabel=str(prior+i+1), facecolor=colors.next(), prior=prior+i, connect=(1, 0), alpha=0.5) def corner(sankey): + """Generate a corner link. + """ prior = len(sankey.diagrams) sankey.add(flows=[1, -1], orientations=[0, 1], patchlabel=str(prior), facecolor='k', prior=prior-1, connect=(1, 0), alpha=0.5) fig = plt.figure() ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Why would you want to do this?" \ - "\n(But you could.)") + title="Why would you want to do this?\n(But you could.)") sankey = Sankey(ax=ax, unit=None) sankey.add(flows=[1, -1], orientations=[0, 1], patchlabel="0", facecolor='k', @@ -124,26 +115,20 @@ def corner(sankey): # Notice: # 1. The alignment doesn't drift significantly (if at all; with 16007 # subdiagrams there is still closure). -# 2. The first diagram is rotated 45 degrees, so all other diagrams are -# rotated accordingly. +# 2. The first diagram is rotated 45 deg, so all other diagrams are rotated +# accordingly. # Example 5 -# This demonstrates a practical example -- a Rankine power cycle. +# This is a practical example of a Rankine power cycle. fig = plt.figure(figsize=(8, 12)) ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") -Hdot = np.array([260.431, 35.078, 180.794, 221.115, 22.700, +Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, 142.361, 10.193, 10.210, 43.670, 44.312, 68.631, 10.758, 10.758, 0.017, 0.642, - 232.121, 44.559, 100.613, 132.168])*1.0e6 # W -sankey = Sankey(ax=ax, format='%.3G', unit='W', gap=0.5, scale=1.0/Hdot[0]) -# Shared copy: -#Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, -# 142.361, 10.193, 10.210, 43.670, 44.312, -# 68.631, 10.758, 10.758, 0.017, 0.642, -# 232.121, 44.559, 100.613, 132.168] # MW -#sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) + 232.121, 44.559, 100.613, 132.168] # MW +sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', flows=[Hdot[13], Hdot[6], -Hdot[7]], labels=['Shaft power', '', None], @@ -199,10 +184,6 @@ def corner(sankey): diagram.text.set_fontweight('bold') diagram.text.set_fontsize('10') for text in diagram.texts: - # Without namedtuple: - #diagram[4].set_fontweight('bold') - #diagram[4].set_fontsize('10') - #for text in diagram[5]: text.set_fontsize('10') # Notice that the explicit connections are handled automatically, but the # implicit ones currently are not. The lengths of the paths and the trunks diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py index f142115fb0e7..6710d09991b2 100644 --- a/lib/matplotlib/sankey.py +++ b/lib/matplotlib/sankey.py @@ -4,7 +4,7 @@ __author__ = "Kevin L. Davies" __credits__ = ["Yannick Copin"] __license__ = "BSD" -__version__ = "2011/09/07" +__version__ = "2011/09/16" # Original version by Yannick Copin (ycopin@ipnl.in2p3.fr) 10/2/2010, available # at: # http://matplotlib.sourceforge.net/examples/api/sankey_demo_old.html @@ -22,7 +22,7 @@ # to automatically justify them # --The call structure was changed to make the specification of path # orientation more flexible. Flows are passed through one array, with -# inputs being positive and outputs being negative. An orientation argment +# inputs being positive and outputs being negative. An orientation argument # specifies the direction of the arrows. The "main" inputs/outputs are now # specified via an orientation of 0, and there may be several of each. # --Added assertions to catch common calling errors @@ -33,30 +33,21 @@ # --Allowed the diagram to be rotated import numpy as np +import warnings + from matplotlib.cbook import iterable, Bunch from matplotlib.path import Path from matplotlib.patches import PathPatch from matplotlib.transforms import Affine2D from matplotlib import verbose -#from collections import namedtuple -# Note: If you cannot use namedtuple (it was introduced in Python 2.6), then -# comment out the line above and switch out the commented code wherever -# "Without namedtuple" is written in the code that follows. -# Angles (in deg/90) +# Angles [deg/90] RIGHT = 0 UP = 1 # LEFT = 2 DOWN = 3 -# Container class for information about a simple Sankey diagram, i.e., one with -# inputs/outputs at a single hierarchial level -#SankeyInfo = namedtuple('SankeyInfo', 'patch flows angles tips text texts') -# Without namedtuple: Comment out the line above. -# See Sankey.finish() for a description of the fields. - - class Sankey: """Sankey diagram in matplotlib @@ -66,17 +57,27 @@ class Sankey: --http://en.wikipedia.org/wiki/Sankey_diagram, accessed 6/1/2011 """ def _arc(self, quadrant=0, cw=True, radius=1, center=(0,0)): - """Return the codes and vertices for a rotated, scaled, and translated + """ + call signature:: + + _arc(quadrant=0, cw=True, radius=1, center=(0,0)) + + Return the codes and vertices for a rotated, scaled, and translated 90 degree arc. - quadrant: Uses 0-based indexing (0, 1, 2, or 3) - cw: If True, clockwise - center: (x, y) tuple of the arc's center + Optional keyword arguments: - Note: It would be possible to use matplotlib's transforms to do this, - but since the rotations is discrete, it's just as easy and maybe more - efficient to do it here. + =============== ========================================== + Keyword Description + =============== ========================================== + *quadrant* uses 0-based indexing (0, 1, 2, or 3) + *cw* if True, clockwise + *center* (x, y) tuple of the arc's center + =============== ========================================== """ + # Note: It would be possible to use matplotlib's transforms to rotate, + # scale, and translate the arc, but since the angles are discrete, + # it's just as easy and maybe more efficient to do it here. ARC_CODES = [Path.LINETO, Path.CURVE4, Path.CURVE4, @@ -92,21 +93,21 @@ def _arc(self, quadrant=0, cw=True, radius=1, center=(0,0)): [7.07106781e-01, 7.07106781e-01], [5.19642327e-01, 8.94571235e-01], [2.65114773e-01, 1.00000000e+00], - #[6.12303177e-17, 1.00000000e+00]]) + #[6.12303177e-17, 1.00000000e+00]]) # Insignificant [0.00000000e+00, 1.00000000e+00]]) if quadrant == 0 or quadrant == 2: if cw: vertices = ARC_VERTICES else: - vertices = ARC_VERTICES[:,::-1] # Swap x and y + vertices = ARC_VERTICES[:,::-1] # Swap x and y. elif quadrant == 1 or quadrant == 3: - # Negate x + # Negate x. if cw: - # Swap x and y + # Swap x and y. vertices = np.column_stack((-ARC_VERTICES[:,1], ARC_VERTICES[:,0])) else: vertices = np.column_stack((-ARC_VERTICES[:,0], ARC_VERTICES[:,1])) - if quadrant > 1: radius = -radius # Rotate 180 deg + if quadrant > 1: radius = -radius # Rotate 180 deg. return zip(ARC_CODES, radius*vertices + np.tile(center, (ARC_VERTICES.shape[0], 1))) @@ -116,7 +117,7 @@ def _add_input(self, path, angle, flow, length): if angle is None: return [0, 0], [0, 0] else: - (x, y) = path[-1][1] # Use the last point as a reference. + (x, y) = path[-1][1] # Use the last point as a reference. dipdepth = (flow / 2) * self.pitch if angle == RIGHT: x -= length @@ -126,17 +127,17 @@ def _add_input(self, path, angle, flow, length): (Path.LINETO, [x, y + flow]), (Path.LINETO, [x+self.gap, y + flow])]) label_location = [dip[0] - self.offset, dip[1]] - else: # Vertical + else: # Vertical x -= self.gap - if angle==UP: sign = 1 + if angle == UP: sign = 1 else: sign = -1 dip = [x - flow / 2, y - sign * (length - dipdepth)] - if angle==DOWN: q = 2 - else: q = 1 + if angle == DOWN: quadrant = 2 + else: quadrant = 1 - if self.radius: # Inner arc not needed if inner radius is zero - path.extend(self._arc(quadrant=q, + if self.radius: # Inner arc isn't needed if inner radius is zero + path.extend(self._arc(quadrant=quadrant, cw=angle==UP, radius=self.radius, center=(x + self.radius, @@ -146,7 +147,7 @@ def _add_input(self, path, angle, flow, length): path.extend([(Path.LINETO, [x, y - sign * length]), (Path.LINETO, dip), (Path.LINETO, [x - flow, y - sign * length])]) - path.extend(self._arc(quadrant=q, + path.extend(self._arc(quadrant=quadrant, cw=angle==DOWN, radius=flow + self.radius, center=(x + self.radius, @@ -159,12 +160,12 @@ def _add_input(self, path, angle, flow, length): def _add_output(self, path, angle, flow, length): """Append an output to a path and return its tip and label locations. - Note: flow is negative for an output. + Note: *flow* is negative for an output. """ if angle is None: return [0, 0], [0, 0] else: - (x, y) = path[-1][1] # Use the last point as a reference. + (x, y) = path[-1][1] # Use the last point as a reference. tipheight = (self.shoulder - flow / 2) * self.pitch if angle == RIGHT: x += length @@ -176,18 +177,18 @@ def _add_output(self, path, angle, flow, length): (Path.LINETO, [x, y + flow]), (Path.LINETO, [x-self.gap, y + flow])]) label_location = [tip[0] + self.offset, tip[1]] - else: # Vertical + else: # Vertical x += self.gap - if angle==UP: sign = 1 + if angle == UP: sign = 1 else: sign = -1 tip = [x - flow / 2.0, y + sign * (length + tipheight)] - if angle==UP: - q = 3 + if angle == UP: + quadrant = 3 else: - q = 0 - if self.radius: # Inner arc not needed if inner radius is zero - path.extend(self._arc(quadrant=q, + quadrant = 0 + if self.radius: # Inner arc isn't needed if inner radius is zero + path.extend(self._arc(quadrant=quadrant, cw=angle==UP, radius=self.radius, center=(x - self.radius, @@ -199,7 +200,7 @@ def _add_output(self, path, angle, flow, length): (Path.LINETO, tip), (Path.LINETO, [x + self.shoulder - flow, y + sign * length]), (Path.LINETO, [x - flow, y + sign * length])]) - path.extend(self._arc(quadrant=q, + path.extend(self._arc(quadrant=quadrant, cw=angle==DOWN, radius=self.radius - flow, center=(x - self.radius, @@ -210,7 +211,7 @@ def _add_output(self, path, angle, flow, length): def _revert(self, path, first_action=Path.LINETO): """A path is not simply revertable by path[::-1] since the code - specifies an action to take from the _previous_ point. + specifies an action to take from the **previous** point. """ reverse_path = [] next_code = first_action @@ -225,150 +226,155 @@ def _revert(self, path, first_action=Path.LINETO): #path[2] = path[2][::-1] #return path - def add(self, patchlabel='', - flows=np.array([1.0,-1.0]), orientations=[0,0], labels='', - trunklength=1.0, pathlengths=0.25, prior=None, connect=(0,0), - rotation=0, **kwargs): - """Add a simple Sankey diagram with flows at the same hierarchial level. - - patchlabel: Label to be placed at the center of the diagram - Note: label (not patchlabel) will be passed the patch - through **kwargs below and can be used to create an - entry in the legend. - flows: Array of flow values - By convention, inputs are positive and outputs are - negative. - orientations: List of orientations of the paths. - The values should be 1 (from/to the top), 0 (from/to a - the left or right), or -1 (from/to the bottom). If 0, - inputs will break in from the left and outputs will break - away to the right. - labels: List of specifications of the labels for the flows - Each value may be None (no labels), '' (just label the - quantities), or a labeling string. If a single value is - provided, it will be applied to all flows. If an entry - is a non-empty string, then the quantity for the - corresponding flow will be shown below the string. - However, if the unit of the main diagram is None, then - quantities are never shown, regardless of the value of - this argument. - trunklength: Length between the bases of the input and output groups - pathlengths: List of lengths of the arrows before break-in or after - break-away - If a single value is given, then it will be applied to - the first (inside) paths on the top and bottom, and the - length of all other arrows will be justified accordingly. - Ths pathlengths are not applied to the hoizontal inputs - and outputs. - prior: Index of the prior diagram to which this diagram should - be connected - connect: A (prior, this) tuple indexing the flow of the prior - diagram and the flow of this diagram which should be - connected - If this is the first diagram or prior is None, connect - will be ignored. - rotation: Angle of rotation of the diagram [deg] - rotation is ignored if this diagram is connected to an - existing one (using prior and connect). The - interpretation of the orientations argument will be - rotated accordingly (e.g., if rotation == 90, an - orientations entry of 1 means to/from the left). - **kwargs: Propagated to matplotlib.patches.PathPatch (e.g., - fill=False, label="A legend entry") - By default, facecolor='#bfd1d4' (light blue) and - lineweight=0.5. - - The indexing parameters (prior and connect) are zero-based. + def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0], + labels='', trunklength=1.0, pathlengths=0.25, prior=None, + connect=(0,0), rotation=0, **kwargs): + """ + call signature:: + + add(patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0], + labels='', trunklength=1.0, pathlengths=0.25, prior=None, + connect=(0,0), rotation=0, **kwargs) + + Add a simple Sankey diagram with flows at the same hierarchical level. + + Return value is the instance of :class:`Sankey`. + + Optional keyword arguments: + + =============== ========================================== + Keyword Description + =============== ========================================== + *patchlabel* label to be placed at the center of the diagram + Note: *label* (not *patchlabel*) will be passed to + the patch through **kwargs and can be used to create + an entry in the legend. + *flows* array of flow values + By convention, inputs are positive and outputs are + negative. + *orientations* list of orientations of the paths + Valid values are 1 (from/to the top), 0 (from/to the + left or right), or -1 (from/to the bottom). If + *orientations* == 0, inputs will break in from the + left and outputs will break away to the right. + *labels* list of specifications of the labels for the flows + Each value may be None (no labels), '' (just label + the quantities), or a labeling string. If a single + value is provided, it will be applied to all flows. + If an entry is a non-empty string, then the quantity + for the corresponding flow will be shown below the + string. However, if the *unit* of the main diagram + is None, then quantities are never shown, regardless + of the value of this argument. + *trunklength* length between the bases of the input and output + groups + *pathlengths* list of lengths of the arrows before break-in or + after break-away + If a single value is given, then it will be applied + to the first (inside) paths on the top and bottom, + and the length of all other arrows will be justified + accordingly. The *pathlengths* are not applied to + the horizontal inputs and outputs. + *prior* index of the prior diagram to which this diagram + should be connected + *connect* a (prior, this) tuple indexing the flow of the prior + diagram and the flow of this diagram which should be + connected + If this is the first diagram or *prior* is None, + *connect* will be ignored. + *rotation* angle of rotation of the diagram [deg] + *rotation* is ignored if this diagram is connected + to an existing one (using *prior* and *connect*). + The interpretation of the *orientations* argument + will be rotated accordingly (e.g., if *rotation* + == 90, an *orientations* entry of 1 means to/from + the left). + =============== ========================================== + + Valid kwargs are :meth:`~matplotlib.patches.PathPatch` arguments: + %(PathPatch)s + As examples, *fill*=False and *label*="A legend entry". By default, + *facecolor*='#bfd1d4' (light blue) and *lineweight*=0.5. + + The indexing parameters (*prior* and *connect*) are zero-based. The flows are placed along the top of the diagram from the inside out in - order of their index within the flows list or array. They are placed + order of their index within the *flows* list or array. They are placed along the sides of the diagram from the top down and along the bottom from the outside in. - If the the sum of the inputs and outputs is not zero, the discrepancy - will show as a cubic Bezier curve along the top and bottom edges of the - trunk. + If the the sum of the inputs and outputs is nonzero, the discrepancy + will appear as a cubic Bezier curve along the top and bottom edges of + the trunk. + + .. seealso:: + + :meth:`finish` """ # Check and preprocess the arguments. flows = np.array(flows) - n = flows.shape[0] # Number of flows + n = flows.shape[0] # Number of flows if rotation == None: rotation = 0 else: rotation /= 90.0 # In the code below, angles are expressed in deg/90. - assert len(orientations) == n, \ - "orientations and flows must have the same length.\n" \ - + "orientations has length " + str(len(orientations)) \ - + ", but flows has length " + str(n) + "." + assert len(orientations) == n, ("orientations and flows must have the " + "same length.\norientations has length " + "%d, but flows has length %d." + % len(orientations), n) if getattr(labels, '__iter__', False): # iterable() isn't used because it would give True if labels is a string. - assert len(labels) == n, \ - "If labels is a list, then labels and flows must " \ - + "have the same length.\nlabels has length " \ - + str(len(labels)) + ", but flows has length " + str(n) + "." + assert len(labels) == n, ("If labels is a list, then labels and " + "flows must have the same length.\n" + "labels has length %d, but flows has " + "length %d." % len(labels), n) else: labels = [labels]*n - assert trunklength >= 0, \ - "trunklength is negative.\n" \ - + "This isn't allowed because it would cause poor layout." + assert trunklength >= 0, ("trunklength is negative.\nThis isn't " + "allowed, because it would cause poor " + "layout.") if np.absolute(np.sum(flows)) > self.tolerance: - verbose.report("The sum of the flows is nonzero (" \ - + str(np.sum(flows)) + ").\nIs the system not at steady state?", - 'helpful') + verbose.report("The sum of the flows is nonzero (%f).\nIs the " + "system not at steady state?" % np.sum(flows), + 'helpful') scaled_flows = self.scale*flows gain = sum(max(flow, 0) for flow in scaled_flows) loss = sum(min(flow, 0) for flow in scaled_flows) if not (0.5 <= gain <= 2.0): - verbose.report("The scaled sum of the inputs is " + str(gain) \ - + ".\nThis may cause poor layout.\nConsider changing the " \ - "scale so that the scaled sum is approximately 1.0.", - 'helpful') + verbose.report("The scaled sum of the inputs is %f.\nThis may " + "cause poor layout.\nConsider changing the scale so " + "that the scaled sum is approximately 1.0." % gain, + 'helpful') if not (-2.0 <= loss <= -0.5): - verbose.report("The scaled sum of the outputs is " + str(gain) \ - + ".\nThis may cause poor layout.\nConsider changing the " \ - "scale so that the scaled sum is approximately 1.0.", - 'helpful') + verbose.report("The scaled sum of the outputs is %f.\nThis may " + "cause poor layout.\nConsider changing the scale so " + "that the scaled sum is approximately 1.0." % gain, + 'helpful') if prior is not None: - assert prior >= 0, \ - "The index of the prior diagram is negative." - assert min(connect) >= 0, \ - "At least one of the connection indices is negative." - assert prior < len(self.diagrams), \ - "The index of the prior diagram is " + str(prior) \ - + " but there are only " + str(len(self.diagrams)) \ - + " other diagrams.\nThe index is zero-based." + assert prior >= 0, "The index of the prior diagram is negative." + assert min(connect) >= 0, ("At least one of the connection indices " + "is negative.") + assert prior < len(self.diagrams), ("The index of the prior " + "diagram is %d, but there are " + "only %d other diagrams.\nThe " + "index is zero-based." % prior, + len(self.diagrams)) assert connect[0] < len(self.diagrams[prior].flows), \ - "The connection index to the source diagram is " \ - + str(connect[0]) + " but that diagram has only " \ - + str(len(self.diagrams[prior].flows)) \ - + " flows.\nThe index is zero-based." - # Without namedtuple: - #assert connect[0] < len(self.diagrams[prior][1]), \ - # "The connection index to the source diagram is " \ - # + str(connect[0]) + " but that diagram has only " \ - # + len(self.diagrams[prior][1]) \ - # + " flows.\nThe index is zero-based." - assert connect[1] < n, \ - "The connection index to this diagram is " \ - + str(connect[1]) + " but this diagram has only " \ - + str(n) + " flows.\nThe index is zero-based." + ("The connection index to the source diagram is %d, but " + "that diagram has only %d flows.\nThe index is zero-based." + % connect[0], len(self.diagrams[prior].flows)) + assert connect[1] < n, ("The connection index to this diagram is " + "%d, but this diagram has only %d flows.\n" + "The index is zero-based." % connect[1], n) assert self.diagrams[prior].angles[connect[0]] is not None, \ - "The connection cannot be made. Check that the magnitude " \ - "of flow " + str(connect[0]) + " of diagram " + str(prior) \ - + "is greater than or equal to the specified tolerance." + ("The connection cannot be made. Check that the magnitude " + "of flow %d of diagram %d is greater than or equal to the " + "specified tolerance." % connect[0], prior) flow_error = self.diagrams[prior].flows[connect[0]] \ + flows[connect[1]] - # Without namedtuple: - #assert self.diagrams[prior][2][connect[0]] is not None, \ - # "The connection cannot be made. Check that the magnitude " \ - # "of flow " + str(connect[0]) + " of diagram " + str(prior) \ - # + "is greater than or equal to the specified tolerance." - #flow_error = self.diagrams[prior][1][connect[0]] \ - # + flows[connect[1]] assert abs(flow_error) < self.tolerance, \ - "The scaled sum of the connected flows is " \ - + str(flow_error) + ", which is not within the tolerance (" \ - + str(self.tolerance) + ")." + ("The scaled sum of the connected flows is %f, which is not " + "within the tolerance (%f)." % flow_error, self.tolerance) # Determine if the flows are inputs. are_inputs = [None]*n @@ -378,10 +384,10 @@ def add(self, patchlabel='', elif flow <= -self.tolerance: are_inputs[i] = False else: - verbose.report("The magnitude of flow " + str(i) + " (" \ - + str(flow) + ") is below the tolerance (" \ - + str(self.tolerance) + ").\nIt will not be shown, and " \ - + "it cannot be used in a connection.", 'helpful') + verbose.report("The magnitude of flow %d (%f) is below the " + "tolerance (%f).\nIt will not be shown, and it " + "cannot be used in a connection." % (i, flow, + self.tolerance), 'helpful') # Determine the angles of the arrows (before rotation). angles = [None]*n @@ -389,15 +395,14 @@ def add(self, patchlabel='', if orient == 1: if is_input: angles[i] = DOWN - elif is_input == False: # Be specific since is_input can be None. + elif is_input == False: # Be specific since is_input can be None. angles[i] = UP elif orient == 0: if is_input is not None: angles[i] = RIGHT else: - assert orient == -1, \ - "The value of orientations[" + str(i) + "] is " \ - + str(orient) + ", but it must be -1, 0, or 1." + assert orient == -1, ("The value of orientations[%d] is %d, " + "but it must be -1, 0, or 1." % i, orient) if is_input: angles[i] = UP elif is_input == False: @@ -405,10 +410,11 @@ def add(self, patchlabel='', # Justify the lengths of the paths. if iterable(pathlengths): - assert len(pathlengths) == n, \ - "If pathlengths is a list, then pathlengths and flows must " \ - "have the same length.\npathlengths has length " \ - + str(len(pathlengths)) + ", but flows has length " + str(n) + "." + assert len(pathlengths) == n, ("If pathlengths is a list, then " + "pathlengths and flows must have " + "the same length.\npathlengths has " + "length %d, but flows has length %d." + % len(pathlengths), n) else: # Make pathlengths into a list. urlength = pathlengths ullength = pathlengths @@ -424,7 +430,7 @@ def add(self, patchlabel='', ullength += flow elif angle == UP and not is_input: pathlengths[i] = urlength - urlength -= flow # Flow is negative for outputs + urlength -= flow # Flow is negative for outputs. # Determine the lengths of the bottom-side arrows from the middle outwards. for i, (angle, is_input, flow) \ in enumerate(zip(angles, are_inputs, scaled_flows)[::-1]): @@ -437,7 +443,8 @@ def add(self, patchlabel='', # Determine the lengths of the left-side arrows from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) \ - in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))[::-1]): + in enumerate(zip(angles, are_inputs, zip(scaled_flows, + pathlengths))[::-1]): if angle == RIGHT: if is_input: if has_left_input: @@ -447,7 +454,8 @@ def add(self, patchlabel='', # Determine the lengths of the right-side arrows from the top downwards. has_right_output = False for i, (angle, is_input, spec) \ - in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))): + in enumerate(zip(angles, are_inputs, zip(scaled_flows, + pathlengths))): if angle == RIGHT: if not is_input: if has_right_output: @@ -457,7 +465,7 @@ def add(self, patchlabel='', # Begin the subpaths, and smooth the transition if the sum of the flows # is nonzero. - urpath = [(Path.MOVETO, [(self.gap - trunklength / 2.0), # Upper right + urpath = [(Path.MOVETO, [(self.gap - trunklength / 2.0), # Upper right gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0) / 2.0, gain / 2.0]), @@ -469,7 +477,7 @@ def add(self, patchlabel='', -loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap), -loss / 2.0])] - llpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower left + llpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower left loss / 2.0]), (Path.LINETO, [(trunklength / 2.0 - self.gap) / 2.0, loss / 2.0]), @@ -481,9 +489,9 @@ def add(self, patchlabel='', -gain / 2.0]), (Path.LINETO, [(self.gap - trunklength / 2.0), -gain / 2.0])] - lrpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower right + lrpath = [(Path.LINETO, [(trunklength / 2.0 - self.gap), # Lower right loss / 2.0])] - ulpath = [(Path.LINETO, [self.gap - trunklength / 2.0, # Upper left + ulpath = [(Path.LINETO, [self.gap - trunklength / 2.0, # Upper left gain / 2.0])] # Add the subpaths and assign the locations of the tips and labels. @@ -534,8 +542,8 @@ def add(self, patchlabel='', urpath.pop() # Concatenate the subpaths in the correct order (clockwise from top). - path = urpath + self._revert(lrpath) + llpath + self._revert(ulpath) \ - + [(Path.CLOSEPOLY, urpath[0][1])] + path = (urpath + self._revert(lrpath) + llpath + self._revert(ulpath) + + [(Path.CLOSEPOLY, urpath[0][1])]) # Create a patch with the Sankey outline. codes, vertices = zip(*path) @@ -554,22 +562,17 @@ def _get_angle(a, r): text = self.ax.text(0, 0, s=patchlabel, ha='center', va='center') else: rotation = self.diagrams[prior].angles[connect[0]] - angles[connect[1]] - # Without namedtuple: - #rotation = self.diagrams[prior][2][connect[0]] \ - # - angles[connect[1]] angles = [_get_angle(angle, rotation) for angle in angles] rotate = Affine2D().rotate_deg(rotation*90).transform_point tips = rotate(tips) offset = self.diagrams[prior].tips[connect[0]] - tips[connect[1]] - # Without namedtuple: - #offset = self.diagrams[prior][3][connect[0]] - tips[connect[1]] translate = Affine2D().translate(*offset).transform_point tips = translate(tips) label_locations = translate(rotate(label_locations)) vertices = translate(rotate(vertices)) kwds = dict(s=patchlabel, ha='center', va='center') text = self.ax.text(*offset, **kwds) - if False: # DEBUG + if False: # Debug print "llpath\n", llpath print "ulpath\n", self._revert(ulpath) print "urpath\n", urpath @@ -577,8 +580,8 @@ def _get_angle(a, r): xs, ys = zip(*vertices) self.ax.plot(xs, ys, 'go-') patch = PathPatch(Path(vertices, codes), - fc=kwargs.pop('fc', kwargs.pop('facecolor', # Custom - '#bfd1d4')), # defaults + fc=kwargs.pop('fc', kwargs.pop('facecolor', # Custom defaults + '#bfd1d4')), lw=kwargs.pop('lw', kwargs.pop('linewidth', '0.5')), **kwargs) @@ -615,33 +618,52 @@ def _get_angle(a, r): # Add this diagram as a subdiagram. self.diagrams.append(Bunch(patch=patch, flows=flows, angles=angles, tips=tips, text=text, texts=texts)) - # Without namedtuple: - #self.diagrams.append((patch, flows, angles, tips, text, texts)) # Allow a daisy-chained call structure (see docstring for the class). return self def finish(self): - """Adjust the axes and return a list of information about the + """ + call signature:: + + finish() + + Adjust the axes and return a list of information about the Sankey subdiagram(s). - Each entry in the subdiagram list is a namedtuple with the following + Return value is a list of subdiagrams represented with the following fields: - patch: Sankey outline (an instance of maplotlib.patches.PathPatch) - flows: Values of the flows (positive for input, negative for output) - angles: List of angles of the arrows [deg/90] - For example, if the diagram has not been rotated, an input to - the top side will have an angle of 3 (DOWN), and an output from - the top side will have an angle of 1 (UP). If a flow has been - skipped (because it is too close to 0), then its angle will be - None. - tips: Array where each row is an [x, y] pair indicating the positions - of the tips (or "dips") of the flow paths - If the magnitude of a flow is less the tolerance for the Sankey - class, the flow is skipped and its tip will be at the center of - the diagram. - text: matplotlib.text.Text instance for the label of the diagram - texts: List of matplotlib.text.Text instances for the labels of flows + + =============== ========================================== + Field Description + =============== ========================================== + *patch* Sankey outline (an instance of + :class:`~maplotlib.patches.PathPatch`) + *flows* values of the flows (positive for input, negative + for output) + *angles* list of angles of the arrows [deg/90] + For example, if the diagram has not been rotated, an + input to the top side will have an angle of 3 + (DOWN), and an output from the top side will have an + angle of 1 (UP). If a flow has been skipped + (because its magnitude is less than *tolerance*), + then its angle will be None. + *tips* array in which each row is an [x, y] pair indicating + the positions of the tips (or "dips") of the flow + paths + If the magnitude of a flow is less the *tolerance* + for the instance of :class:`Sankey`, the flow is + skipped and its tip will be at the center of the + diagram. + *text* :class:`~matplotlib.text.Text` instance for the + label of the diagram + *texts* list of :class:`~matplotlib.text.Text` instances for + the labels of flows + =============== ========================================== + + .. seealso:: + + :meth:`add` """ self.ax.axis([self.extent[0] - self.margin, self.extent[1] + self.margin, @@ -653,71 +675,94 @@ def finish(self): def __init__(self, ax=None, scale=1.0, unit='', format='%G', gap=0.25, radius=0.1, shoulder=0.03, offset=0.15, head_angle=100, margin=0.4, tolerance=1e-6, **kwargs): - """Create a new Sankey diagram. - - ax: Axes onto which the data should be plotted - If not provided, they will be created. - scale: Scaling factor for the flows - This factor sizes the width of the paths in order to - maintain proper layout. The same scale is applied to all - subdiagrams. The value should be chosen such that the - product of the scale and the sum of the inputs is - approximately 1 (and the product of the scale and the sum - of the outputs is approximately -1). - unit: Unit associated with the flow quantities - If unit is None, then none of the quantities are labeled. - format: A Python number formatting string to be used in labeling - the flow as a quantity (i.e., a number times a unit, where - the unit is given) - gap: Space between paths in that break in/break away to/from - the top or bottom - radius: Inner radius of the vertical paths - shoulder: Output arrow shoulder - offset: Text offset (away from the dip or tip of the arrow) - head_angle: Angle of the arrow heads (and negative of the angle of the - tails) [deg] - margin: Minimum space between Sankey outlines and the edge of the - plot area - tolerance: Acceptable maximum of the magnitude of the sum of flows - The magnitude of the sum of connected flows cannot be - greater than this value. If the magnitude of the sum of - the flows of a subdiagram is greater than this value, a - warning is displayed. - **kwargs: Propagated to Sankey.add() - - The above arguments are applied to all subdiagrams so that there is - consistent alignment and formatting. - - If this class is instantiated with any keyworded arguments (**kwargs) - other than those explicitly listed above, they will be passed to the - add() method, which will create the first subdiagram. - - In order to draw a complex Sankey diagram, create an instance of this - class by calling it without any **kwargs: - sankey = Sankey() + """ + call signature:: + + Sankey(ax=None, scale=1.0, unit='', format='%G', gap=0.25, radius=0.1, + shoulder=0.03, offset=0.15, head_angle=100, margin=0.4, + tolerance=1e-6, **kwargs) + + Create a new Sankey diagram. + + Return value is an instance of :class:`Sankey`. + + Optional keyword arguments: + + =============== ========================================== + Field Description + =============== ========================================== + *ax* axes onto which the data should be plotted + If *ax* isn't provided, new axes will be created. + *scale* scaling factor for the flows + *scale* sizes the width of the paths in order to + maintain proper layout. The same scale is applied + to all subdiagrams. The value should be chosen such + that the product of the scale and the sum of the + inputs is approximately 1.0 (and the product of the + scale and the sum of the outputs is approximately + -1.0). + *unit* string representing the physical unit associated + with the flow quantities + If *unit* is None, then none of the quantities are + labeled. + *format* a Python number formatting string to be used in + labeling the flow as a quantity (i.e., a number + times a unit, where the unit is given) + *gap* space between paths that break in/break away to/from + the top or bottom + *radius* inner radius of the vertical paths + *shoulder* size of the shoulders of output arrowS + *offset* text offset (from the dip or tip of the arrow) + *head_angle* angle of the arrow heads (and negative of the angle + of the tails) [deg] + *margin* minimum space between Sankey outlines and the edge + of the plot area + *tolerance* acceptable maximum of the magnitude of the sum of + flows + The magnitude of the sum of connected flows cannot + be greater than *tolerance*. + =============== ========================================== + + The optional arguments listed above are applied to all subdiagrams so + that there is consistent alignment and formatting. + + If :class:`Sankey` is instantiated with any keyword arguments other than + those explicitly listed above (**kwargs), they will be passed to + :meth:`add`, which will create the first subdiagram. + + In order to draw a complex Sankey diagram, create an instance of + :class:`Sankey` by calling it without any kwargs: + >>> sankey = Sankey() Then add simple Sankey sub-diagrams: - sankey.add() # 1 - sankey.add() # 2 - #... - sankey.add() # n + >>> sankey.add() # 1 + >>> sankey.add() # 2 + >>> #... + >>> sankey.add() # n Finally, create the full diagram: - sankey.finish() + >>> sankey.finish() Or, instead, simply daisy-chain those calls: - Sankey().add().add... .add().finish() + >>> Sankey().add().add... .add().finish() + + .. seealso:: + + :meth:`add` + :meth:`finish` + + **Examples:** + + .. plot:: mpl_examples/api/sankey_demo.py """ # Check the arguments. - assert gap >= 0, \ - "The gap is negative.\n" \ - + "This isn't allowed because it would cause the paths to overlap." - assert radius <= gap, \ - "The inner radius is greater than the path spacing.\n" \ - + "This isn't allowed because it would cause the paths to overlap." - assert head_angle >= 0, \ - "The angle is negative.\n" \ - + "This isn't allowed because it would cause inputs to look "\ - + "like outputs and vice versa." - assert tolerance >= 0, \ - "The tolerance is negative.\nIt must be a magnitude." + assert gap >= 0, ("The gap is negative.\nThis isn't allowed because it " + "would cause the paths to overlap.") + assert radius <= gap, ("The inner radius is greater than the path " + "spacing.\nThis isn't allowed because it would " + "cause the paths to overlap.") + assert head_angle >= 0, ("The angle is negative.\nThis isn't allowed " + "because it would cause inputs to look like " + "outputs and vice versa.") + assert tolerance >= 0, ("The tolerance is negative.\nIt must be a " + "magnitude.") # Create axes if necessary. if ax is None: @@ -746,208 +791,3 @@ class by calling it without any **kwargs: # If there are any kwargs, create the first subdiagram. if len(kwargs): self.add(**kwargs) - -if __name__ == '__main__': - """Demonstrate the Sankey class. - """ - import matplotlib.pyplot as plt - from itertools import cycle - - # Example 1 -- Mostly defaults - # This demonstrates how to create a simple diagram by implicitly calling the - # Sankey.add() method and by appending finish() to the call to the class. - Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], - labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], - orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() - plt.title("The default settings produce a diagram like this.") - # Notice: - # 1. Axes weren't provided when Sankey() was instantiated, so they were - # created automatically. - # 2. The scale argument wasn't necessary since the data was already - # normalized. - # 3. By default, the lengths of the paths are justified. - - # Example 2 - # This demonstrates: - # 1. Setting one path longer than the others - # 2. Placing a label in the middle of the diagram - # 3. Using the the scale argument to normalize the flows - # 4. Implicitly passing keyword arguments to PathPatch() - # 5. Changing the angle of the arrow heads - # 6. Changing the offset between the tips of the paths and their labels - # 7. Formatting the numbers in the path labels and the associated unit - # 8. Changing the appearance of the patch and the labels after the figure - # is created - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Flow Diagram of a Widget") - sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, - format='%.0f', unit='%') - sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], - labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', - 'Fifth', 'Hurray!'], - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], - pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, - 0.25], - patchlabel="Widget\nA", - alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() - diagrams = sankey.finish() - diagrams[0].patch.set_facecolor('#37c959') - diagrams[0].texts[-1].set_color('r') - diagrams[0].text.set_fontweight('bold') - # Without namedtuple: - #diagrams[0][0].set_facecolor('#37c959') - #diagrams[0][5][-1].set_color('r') - #diagrams[0][4].set_fontweight('bold') - # Notice: - # 1. Since the sum of the flows isn't zero, the width of the trunk isn't - # uniform. A message is given in the terminal window. - # 2. The second flow doesn't appear because its value is zero. A messsage - # is given in the terminal window. - - # Example 3 - # This demonstrates: - # 1. Connecting two systems - # 2. Turning off the labels of the quantities - # 3. Adding a legend - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") - flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] - sankey = Sankey(ax=ax, unit=None) - sankey.add(flows=flows, label='one', - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) - sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', - orientations=[-1, -1, -1], prior=0, connect=(0, 0)) - diagrams = sankey.finish() - diagrams[-1].patch.set_hatch('/') - # Without namedtuple: - #diagrams[-1][0].set_hatch('/') - - plt.legend(loc='best') - # Notice that only one connection is specified, but the systems form a - # circuit since: (1) the lengths of the paths are justified and (2) the - # orientation and ordering of the flows is mirrored. - - # Example 4 - # This tests a long chain of connections. - links_per_side = 6 - def side(sankey, n=1): - prior = len(sankey.diagrams) - colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) - for i in range(0, 2*n, 2): - sankey.add(flows=[1, -1], orientations=[-1, -1], - patchlabel=str(prior+i), facecolor=colors.next(), - prior=prior+i-1, connect=(1, 0), alpha=0.5) - sankey.add(flows=[1, -1], orientations=[1, 1], - patchlabel=str(prior+i+1), facecolor=colors.next(), - prior=prior+i, connect=(1, 0), alpha=0.5) - def corner(sankey): - prior = len(sankey.diagrams) - sankey.add(flows=[1, -1], orientations=[0, 1], - patchlabel=str(prior), facecolor='k', - prior=prior-1, connect=(1, 0), alpha=0.5) - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Why would you want to do this?" \ - "\n(But you could.)") - sankey = Sankey(ax=ax, unit=None) - sankey.add(flows=[1, -1], orientations=[0, 1], - patchlabel="0", facecolor='k', - rotation=45) - side(sankey, n=links_per_side) - corner(sankey) - side(sankey, n=links_per_side) - corner(sankey) - side(sankey, n=links_per_side) - corner(sankey) - side(sankey, n=links_per_side) - sankey.finish() - # Notice: - # 1. The alignment doesn't drift significantly (if at all; with 16007 - # subdiagrams there is still closure). - # 2. The first diagram is rotated 45 degrees, so all other diagrams are - # rotated accordingly. - - # Example 5 - # This demonstrates a practical example -- a Rankine power cycle. - fig = plt.figure(figsize=(8, 12)) - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" - + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") - Hdot = np.array([260.431, 35.078, 180.794, 221.115, 22.700, - 142.361, 10.193, 10.210, 43.670, 44.312, - 68.631, 10.758, 10.758, 0.017, 0.642, - 232.121, 44.559, 100.613, 132.168])*1.0e6 # W - sankey = Sankey(ax=ax, format='%.3G', unit='W', gap=0.5, scale=1.0/Hdot[0]) - # Shared copy: - #Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, - # 142.361, 10.193, 10.210, 43.670, 44.312, - # 68.631, 10.758, 10.758, 0.017, 0.642, - # 232.121, 44.559, 100.613, 132.168] # MW - #sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) - sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', - flows=[Hdot[13], Hdot[6], -Hdot[7]], - labels=['Shaft power', '', None], - pathlengths=[0.4, 0.883, 0.25], - orientations=[1, -1, 0]) - sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', - flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], - labels=[None, '', None, None], - pathlengths=[0.25, 0.25, 1.93, 0.25], - orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) - sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', - flows=[Hdot[14], Hdot[8], -Hdot[9]], - labels=['Shaft power', '', None], - pathlengths=[0.4, 0.25, 0.25], - orientations=[1, 0, 0], prior=1, connect=(3, 1)) - sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', - flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], - pathlengths=[0.25, 1.543, 0.25, 0.25], - labels=['', '', None, None], - orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) - sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, - flows=[Hdot[11], -Hdot[12]], - labels=['\n', None], - pathlengths=[1.0, 1.01], - orientations=[1, 1], prior=3, connect=(2, 0)) - sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', - flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], - labels=['Heat rate', '', '', None, None], - pathlengths=0.25, - orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) - sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', - flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], - labels=['', None, None, None], - pathlengths=[0.25, 0.153, 1.543, 0.25], - orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) - sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', - flows=[Hdot[2], -Hdot[2]], - labels=[None, None], - pathlengths=[0.725, 0.25], - orientations=[-1, 0], prior=6, connect=(3, 0)) - sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', - flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], - labels=[None, 'Shaft power', None, '', 'Shaft power'], - pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], - orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) - sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, - flows=[Hdot[5], -Hdot[18], -Hdot[6]], - labels=['', 'Heat rate', None], - pathlengths=[0.45, 0.25, 0.883], - orientations=[-1, 1, 0], prior=8, connect=(2, 0)) - diagrams = sankey.finish() - for diagram in diagrams: - diagram.text.set_fontweight('bold') - diagram.text.set_fontsize('10') - for text in diagram.texts: - # Without namedtuple: - #diagram[4].set_fontweight('bold') - #diagram[4].set_fontsize('10') - #for text in diagram[5]: - text.set_fontsize('10') - # Notice that the explicit connections are handled automatically, but the - # implicit ones currently are not. The lengths of the paths and the trunks - # must be adjusted manually, and that is a bit tricky. - - plt.show() - From 5bee49aadffd48d5639415481dfe127226ddb35b Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Sat, 17 Sep 2011 22:43:45 +0900 Subject: [PATCH 139/214] fix wrong direction of arrow for arrow stylle ]- --- lib/matplotlib/patches.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index f03468c94aca..6484b793c761 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -3283,7 +3283,7 @@ def __init__(self, widthA=1., lengthA=0.2, angleA=None): angle between the bracket and the line """ - super(ArrowStyle.BracketA, self).__init__(None, True, + super(ArrowStyle.BracketA, self).__init__(True, None, widthA=widthA, lengthA=lengthA, angleA=angleA ) _style_list["]-"] = BracketA From c04da2732133fec613962c9fffc9511697d04f2d Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sat, 17 Sep 2011 10:22:22 -1000 Subject: [PATCH 140/214] doc/make.py: add comments to JJ's patch as suggested by Mike D. --- doc/make.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/make.py b/doc/make.py index 59e89e0906f7..c85d380f8a7b 100755 --- a/doc/make.py +++ b/doc/make.py @@ -5,8 +5,18 @@ import shutil import sys +### Begin compatibility block for pre-v2.6: ### +# # ignore_patterns and copytree funtions are copies of what is included # in shutil.copytree of python v2.6 and later. +# +### When compatibility is no-longer needed, this block +### can be replaced with: +### +### from shutil import ignore_patterns, copytree +### +### or the "shutil." qualifier can be prepended to the function +### names where they are used. try: WindowsError @@ -92,6 +102,8 @@ def copytree(src, dst, symlinks=False, ignore=None): if errors: raise Error, errors +### End compatibility block for pre-v2.6 ### + def copy_if_out_of_date(original, derived): if (not os.path.exists(derived) or From 57a49e59d15856a618301efffb4feda710fdb125 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sat, 17 Sep 2011 15:08:31 -1000 Subject: [PATCH 141/214] fix test_figure, baseline images (testing figure specification by name) --- .../test_figure/figure_today.pdf | Bin 7050 -> 7036 bytes .../test_figure/figure_today.svg | 1239 ++++++++++++----- lib/matplotlib/tests/test_figure.py | 9 +- 3 files changed, 885 insertions(+), 363 deletions(-) diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf index 9fea07616a4128a6fbdcf9c194aa4391fe747a2d..19d8e67af1a2260fc7297c4d2e2a8875405402a2 100644 GIT binary patch delta 1232 zcmeA&|6{hHjIq9Uns5IV1D>|`KSeDMsa`qfe)+Y>hD-Mvyyi@t#=17mL1BsLe>wGS zm(TdzI_&e->TL4%bF&+24Kw6*Z@e$tw7#U)KsZud`nk*X;=OGBDZWL26X#`~X`VST z&q60zarc39kuvi)pMG*t!Sr2X!nYRDNe3tsHto3}~g6*wS{F52P zf7wUJDBX3{D4QX4_Ko_InRy4EZT{&IYIw1{dSjqfykR*IYPGboUaN#7H@eyxzc#&%eArbZ+>4jnZr0IQ)+FaEbFG#K41AZ zGITfpv`raZq7Vc5N+DC%58s!cFYu_}UmHd5FVm#f;nW z8y;yyOlwHX3eiFw} zujk9hcd{@lhR5>G!NV)w_}MP`#d|x5%a`l>LX+9cb(U@{S8b_S$~`lDZLd1xv#mGe z`d6L05q4=^iNJ)?Z9=X^(m~E=?kq~y(2eO>Icp;xaR}+^oyu zFT!JKXl`g^Y;IzzYiKaJLqc6flS|*ZC^fMpzeqtNH?gE3C%+^oGfBZv&rr``@Sj=EM{S5j&8A$p(%z(jf@R2 zEH*MR!*H~bxhXK>5P=>6Vj3HmqX>e)J+TwF&txNWMnqkTH1}%+?-2Q J)z#mP3jkavx;_8^ delta 1249 zcmexk)@8n-jIn<0G~av?L!P$xKSeDsd3((1KN+Ka(d$mbR14*)+g6ozJ9voxms8(n zeDh4ZMZpc({f~X-SvT<-o?5G1-(#>b*{&D@p) z9$fxc6ff<(xg(RcmwC&(i&xup>n~_YPq}JX(sk^n=5E6%b2sj~X(78a#F*4H69U^4 zK6rdkc%X1aF~*B&;iQZ!TGCUm8k#1XJ-fNgFh=6=*NdFnW-;kHO-PYvsy#5JG?ClF z#Y^*?hZxh-FX?MmB!8IG8@)HwzD-g{=jD+_fva;u!rHG0Fz>r+*!fo?JA7LduW)@< z{SN)NE98R~&-LZ8Tyr3iXZva%nXgSbr#aUydB}z39XxMYqE58$^=&b z{1zeM+g283cADwXio7tX=@;6B#XpL@HxuAr)~%X2F>S%(by-de{Tx(HH{J}qdGyM& zyNjKavQDX4-40z;x@M_%NLns`ugCUI^?7&2>pfig=NPZ-E)3=1(mglHIHk;`%y4t% z_Z2fe8lJ1f2VOS}+P*p@ujcg21o1%e_i|fvv=ba(1ZRYDac$a`=@hovc~keqv%94; zEV~cJK0UvR?~ATwDR1o>#)qr!zE@22o7#0$spQH!jtA`F=VkUQo1MD!=+3_vyNYz? z$COU};kn3d{w*zUo~6uF+q_@TvE|d%{`2?o!`t$ai+^!jmvY!}rRJp+mlUNY=7L!H zNm*Qmh6)A>AcmQlIb6(a@CWa;^2F4cJ21b(`B-E7@iY$yQjWoIR zoq@)bKW)6PChJ=kY;Y8U;qLNc?w)$hJl%ZsRgE(r2&SR zA;?W=dJT<@FvU!bCwEHv)tj25OPN@hU>IRyW@Lt;&InV?)WQ4pa87 + - diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index 299efc69ab56..e042ac73cac1 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -32,7 +32,8 @@ def test_figure(): ax = fig.add_subplot(111) ax.set_title(fig.get_label()) ax.plot(range(5)) - fig = plt.figure('tomorow') - plt.plot([0], 'or') - fig = plt.figure('today') - fig.savefig('figure_today') + # plot red line in a different figure. + plt.figure('tomorow') + plt.plot([0, 1], [1,0], 'r') + # Return to the original; make sure the red line is not there. + plt.figure('today') From fcc8039b3468e17310a519a22159a7a06b4d4d4b Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee - - + - - - - - - - - - - - - - - - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Date: Sun, 18 Sep 2011 15:20:46 +0900 Subject: [PATCH 142/214] axisartist: implement LocatorDM, LocatorD, LocatorHM, LocatorH and update FormatterHMS and FormaterDMS --- lib/mpl_toolkits/axisartist/angle_helper.py | 245 ++++++++++++++------ 1 file changed, 175 insertions(+), 70 deletions(-) diff --git a/lib/mpl_toolkits/axisartist/angle_helper.py b/lib/mpl_toolkits/axisartist/angle_helper.py index 0da37420f1fd..a07c961f3941 100644 --- a/lib/mpl_toolkits/axisartist/angle_helper.py +++ b/lib/mpl_toolkits/axisartist/angle_helper.py @@ -96,7 +96,8 @@ def select_step_sub(dv): return step, factor -def select_step(v1, v2, nv, hour=False, include_last=True): +def select_step(v1, v2, nv, hour=False, include_last=True, + threshold_factor=3600.): if v1 > v2: v1, v2 = v2, v1 @@ -111,14 +112,14 @@ def select_step(v1, v2, nv, hour=False, include_last=True): cycle = 360. # for degree - if dv > 1./3600.: + if dv > 1./threshold_factor: #print "degree" step, factor = _select_step(dv) else: - step, factor = select_step_sub(dv*3600.) + step, factor = select_step_sub(dv*threshold_factor) #print "feac", step, factor - factor = factor * 3600. + factor = factor * threshold_factor f1, f2, fstep = v1*factor, v2*factor, step/factor @@ -148,81 +149,111 @@ def select_step(v1, v2, nv, hour=False, include_last=True): return np.array(levs), n, factor -def select_step24(v1, v2, nv, include_last=True): +def select_step24(v1, v2, nv, include_last=True, threshold_factor=3600): v1, v2 = v1/15., v2/15. levs, n, factor = select_step(v1, v2, nv, hour=True, - include_last=include_last) + include_last=include_last, + threshold_factor=threshold_factor) return levs*15., n, factor -def select_step360(v1, v2, nv, include_last=True): +def select_step360(v1, v2, nv, include_last=True, threshold_factor=3600): return select_step(v1, v2, nv, hour=False, - include_last=include_last) + include_last=include_last, + threshold_factor=threshold_factor) - -class LocatorHMS(object): +class LocatorBase(object): def __init__(self, den, include_last=True): self.den = den self._include_last = include_last + + def _get_nbins(self): + return self.den + + def _set_nbins(self, v): + self.den = v + + nbins = property(_get_nbins, _set_nbins) + + def set_params(self, **kwargs): + if "nbins" in kwargs: + self.den = int(kwargs.pop("nbins")) + + if kwargs: + raise ValueError("Following keys are not processed: %s" % \ + ", ".join([str(k) for k in kwargs.keys()])) + + +class LocatorHMS(LocatorBase): def __call__(self, v1, v2): return select_step24(v1, v2, self.den, self._include_last) +class LocatorHM(LocatorBase): + def __call__(self, v1, v2): + return select_step24(v1, v2, self.den, self._include_last, + threshold_factor=60) -class LocatorDMS(object): - def __init__(self, den, include_last=True): - self.den = den - self._include_last = include_last +class LocatorH(LocatorBase): + def __call__(self, v1, v2): + return select_step24(v1, v2, self.den, self._include_last, + threshold_factor=1) + + +class LocatorDMS(LocatorBase): def __call__(self, v1, v2): return select_step360(v1, v2, self.den, self._include_last) +class LocatorDM(LocatorBase): + def __call__(self, v1, v2): + return select_step360(v1, v2, self.den, self._include_last, + threshold_factor=60) -class FormatterHMS(object): - def __call__(self, direction, factor, values): # hour - if len(values) == 0: - return [] - #ss = [[-1, 1][v>0] for v in values] #not py24 compliant - values = np.asarray(values) - ss = np.where(values>=0, 1, -1) - values = np.abs(values)/15. +class LocatorD(LocatorBase): + def __call__(self, v1, v2): + return select_step360(v1, v2, self.den, self._include_last, + threshold_factor=1) - if factor == 1: - return ["$%s%d^{\mathrm{h}}$" % ({1:"",-1:"-"}[s], int(v),) \ - for s, v in zip(ss, values)] - elif factor == 60: - return ["$%d^{\mathrm{h}}\,%02d^{\mathrm{m}}$" % (s*floor(v/60.), v%60) \ - for s, v in zip(ss, values)] - elif factor == 3600: - if ss[-1] == -1: - inverse_order = True - values = values[::-1] - else: - inverse_order = False - degree = floor(values[0]/3600.) - hm_fmt = "$%d^{\mathrm{h}}\,%02d^{\mathrm{m}}\," - s_fmt = "%02d^{\mathrm{s}}$" - l_hm_old = "" - r = [] - for v in values-3600*degree: - l_hm = hm_fmt % (ss[0]*degree, floor(v/60.)) - l_s = s_fmt % (v%60,) - if l_hm != l_hm_old: - l_hm_old = l_hm - l = l_hm + l_s - else: - l = "$"+l_s - r.append(l) - if inverse_order: - return r[::-1] - else: - return r - #return [fmt % (ss[0]*degree, floor(v/60.), v%60) \ - # for s, v in zip(ss, values-3600*degree)] - else: # factor > 3600. - return [r"$%s^{\mathrm{h}}$" % (str(v),) for v in ss*values] class FormatterDMS(object): + + deg_mark = "^{\circ}" + min_mark = "^{\prime}" + sec_mark = "^{\prime\prime}" + + fmt_d = "$%d"+deg_mark+"$" + fmt_ds = r"$%d.\!\!"+deg_mark+"%s$" + + # %s for signe + fmt_d_m = r"$%s%d"+deg_mark+"\,%02d"+min_mark+"$" + fmt_d_ms = r"$%s%d"+deg_mark+"\,%02d.\mkern-4mu"+min_mark+"%s$" + + + fmt_d_m_partial = "$%s%d"+deg_mark+"\,%02d"+min_mark+"\," + fmt_s_partial = "%02d"+sec_mark+"$" + fmt_ss_partial = "%02d.\!\!"+sec_mark+"%s$" + + + def _get_number_fraction(self, factor): + ## check for fractional numbers + number_fraction = None + # check for 60 + + for threshold in [1, 60, 3600]: + if factor <= threshold: + break + + d = factor // threshold + int_log_d = int(floor(math.log10(d))) + if 10**int_log_d == d and d!=1: + number_fraction = int_log_d + factor = factor // 10**int_log_d + return factor, number_fraction + + return factor, number_fraction + + def __call__(self, direction, factor, values): if len(values) == 0: return [] @@ -233,13 +264,30 @@ def __call__(self, direction, factor, values): sign_map = {(-1, True):"-"} signs = [sign_map.get((s, v!=0), "") for s, v in zip(ss, values)] + factor, number_fraction = self._get_number_fraction(factor) + values = np.abs(values) + if number_fraction is not None: + values, frac_part = divmod(values, 10**number_fraction) + frac_fmt = "%%0%dd" % (number_fraction,) + frac_str = [frac_fmt % (f1,) for f1 in frac_part] + if factor == 1: - return ["$%d^{\circ}$" % (s*int(v),) for (s, v) in zip(ss, values)] + if number_fraction is None: + return [self.fmt_d % (s*int(v),) for (s, v) in zip(ss, values)] + else: + return [self.fmt_ds % (s*int(v), f1) for (s, v, f1) in \ + zip(ss, values, frac_str)] elif factor == 60: - return ["$%s%d^{\circ}\,%02d^{\prime}$" % (s,floor(v/60.), v%60) \ - for s, v in zip(signs, values)] + deg_part, min_part = divmod(values, 60) + if number_fraction is None: + return [self.fmt_d_m % (s1, d1, m1) \ + for s1, d1, m1 in zip(signs, deg_part, min_part)] + else: + return [self.fmt_d_ms % (s, d1, m1, f1) \ + for s, d1, m1, f1 in zip(signs, deg_part, min_part, frac_str)] + elif factor == 3600: if ss[-1] == -1: inverse_order = True @@ -247,29 +295,57 @@ def __call__(self, direction, factor, values): sings = signs[::-1] else: inverse_order = False - degree = floor(values[0]/3600.) - hm_fmt = "$%s%d^{\circ}\,%02d^{\prime}\," - s_fmt = "%02d^{\prime\prime}$" + l_hm_old = "" r = [] - for v, s in zip(values-3600*degree, signs): - l_hm = hm_fmt % (s, degree, floor(v/60.)) - l_s = s_fmt % (v%60,) + + deg_part, min_part_ = divmod(values, 3600) + min_part, sec_part = divmod(min_part_, 60) + + if number_fraction is None: + sec_str = [self.fmt_s_partial % (s1,) for s1 in sec_part] + else: + sec_str = [self.fmt_ss_partial % (s1, f1) for s1, f1 in zip(sec_part, frac_str)] + + for s, d1, m1, s1 in zip(signs, deg_part, min_part, sec_str): + l_hm = self.fmt_d_m_partial % (s, d1, m1) if l_hm != l_hm_old: l_hm_old = l_hm - l = l_hm + l_s + l = l_hm + s1 #l_s else: - l = "$"+l_s + l = "$"+s1 #l_s r.append(l) + if inverse_order: return r[::-1] else: return r - #return [fmt % (ss[0]*degree, floor(v/60.), v%60) \ - # for s, v in zip(ss, values-3600*degree)] + else: # factor > 3600. return [r"$%s^{\circ}$" % (str(v),) for v in ss*values] +class FormatterHMS(FormatterDMS): + deg_mark = "^{\mathrm h}" + min_mark = "^{\mathrm m}" + sec_mark = "^{\mathrm s}" + + fmt_d = "$%d"+deg_mark+"$" + fmt_ds = r"$%d.\!\!"+deg_mark+"%s$" + + # %s for signe + fmt_d_m = r"$%s%d"+deg_mark+"\,%02d"+min_mark+"$" + fmt_d_ms = r"$%s%d"+deg_mark+"\,%02d.\!\!"+min_mark+"%s$" + + + fmt_d_m_partial = "$%s%d"+deg_mark+"\,%02d"+min_mark+"\," + fmt_s_partial = "%02d"+sec_mark+"$" + fmt_ss_partial = "%02d.\!\!"+sec_mark+"%s$" + + + def __call__(self, direction, factor, values): # hour + return FormatterDMS.__call__(self, direction, factor, np.asarray(values)/15.) + + @@ -352,11 +428,40 @@ def _adjust_extremes(self, lon_min, lon_max, lat_min, lat_max): if __name__ == "__main__": #test2() - print select_step360(21.2, 33.3, 5) + #print select_step360(21.2, 33.3, 5) + #print select_step360(20+21.2/60., 21+33.3/60., 5) + #print select_step360(20.5+21.2/3600., 20.5+33.3/3600., 5) + + # test threshold factor + print select_step360(20.5+11.2/3600., 20.5+53.3/3600., 5, + threshold_factor=60) + + print select_step360(20.5+11.2/3600., 20.5+53.3/3600., 5, + threshold_factor=1) + + fmt = FormatterDMS() + #print fmt("left", 60, [0, -30, -60]) + print fmt("left", 600, [12301, 12302, 12303]) + + print select_step360(20.5+21.2/3600., 20.5+21.4/3600., 5) + print fmt("left", 36000, [738210, 738215, 738220]) + print fmt("left", 360000, [7382120, 7382125, 7382130]) + print fmt("left", 1., [45, 46, 47]) + print fmt("left", 10., [452, 453, 454]) + +if 0: print select_step360(20+21.2/60., 21+33.3/60., 5) print select_step360(20.5+21.2/3600., 20.5+33.3/3600., 5) print select_step360(20+21.2/60., 20+53.3/60., 5) + ### + levs, n, factor = select_step360(20.5+21.2/3600., 20.5+27.25/3600., 5) + levs = levs * 0.1 + fmt = FormatterDMS() + #print fmt("left", 60, [0, -30, -60]) + print fmt("left", factor, levs) + + print select_step(-180, 180, 10, hour=False) print select_step(-12, 12, 10, hour=True) From 6923c7f04fbafa23766250d710cc6b37373c816f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Seppa=CC=88nen?= Date: Sun, 18 Sep 2011 16:23:20 +0300 Subject: [PATCH 143/214] Test nearest and none interpolation better Changes the baseline file image_interps.pdf to match the current behavior of the code, and adds a new test for the difference between "nearest" and "none" interpolation. --- .../test_image/image_interps.pdf | Bin 115574 -> 116970 bytes .../test_image/interp_nearest_vs_none.pdf | Bin 0 -> 9141 bytes .../test_image/interp_nearest_vs_none.svg | 1061 +++++++++++++++++ lib/matplotlib/tests/test_image.py | 20 + 4 files changed, 1081 insertions(+) create mode 100644 lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf index 42ea689625a3ef81b6854836ce478c651147a606..eb482fed7fff84d751af4bdb9cb93be95b7e0ca6 100644 GIT binary patch delta 4001 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 DpHdn& diff --git a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf new file mode 100644 index 0000000000000000000000000000000000000000..72148dd959e290bee4ec5d0d71658168a856770d GIT binary patch literal 9141 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg new file mode 100644 index 000000000000..e80eb2436c91 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg @@ -0,0 +1,1061 @@ + + + + diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 40bdab5709df..2c9db8a23e17 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -1,6 +1,7 @@ import numpy as np from matplotlib.testing.decorators import image_comparison, knownfailureif, cleanup +from matplotlib import rcParams import matplotlib.pyplot as plt from nose.tools import assert_raises from numpy.testing import assert_array_equal @@ -28,6 +29,25 @@ def test_image_interps(): ax3.imshow(X, interpolation='bicubic') ax3.set_ylabel('bicubic') +@image_comparison(baseline_images=['interp_nearest_vs_none'], extensions=['pdf', 'svg']) +def test_interp_nearest_vs_none(): + 'Test the effect of "nearest" and "none" interpolation' + # Setting dpi to something really small makes the difference very + # visible. This works fine with pdf, since the dpi setting doesn't + # affect anything but images, but the agg output becomes unusably + # small. + rcParams['savefig.dpi'] = 3 + X = np.array([[[218, 165, 32], [122, 103, 238]], + [[127, 255, 0], [255, 99, 71]]], dtype=np.uint8) + fig = plt.figure() + ax1 = fig.add_subplot(121) + ax1.imshow(X, interpolation='none') + ax1.set_title('interpolation none') + ax2 = fig.add_subplot(122) + ax2.imshow(X, interpolation='nearest') + ax2.set_title('interpolation nearest') + + @image_comparison(baseline_images=['figimage-0', 'figimage-1'], extensions=['png'], tol=1.5e-3) def test_figimage(): 'test the figimage method' From 32a2cdd0ed545404f9c8cb3e2eab4b40b86f3909 Mon Sep 17 00:00:00 2001 From: Eric Firing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Sun, 18 Sep 2011 08:17:18 -1000 Subject: [PATCH 144/214] findobj: add kwarg to prevent duplicates in output. Closes issue #475. --- lib/matplotlib/artist.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 17cc94d83835..9f026e93ebc9 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -728,21 +728,25 @@ def set(self, **kwargs): ret.extend( [func(v)] ) return ret - def findobj(self, match=None): + def findobj(self, match=None, include_self=True): """ pyplot signature: - findobj(o=gcf(), match=None) + findobj(o=gcf(), match=None, include_self=True) Recursively find all :class:matplotlib.artist.Artist instances contained in self. *match* can be - - None: return all objects contained in artist (including artist) + - None: return all objects contained in artist. + + - function with signature ``boolean = match(artist)`` + used to filter matches - - function with signature ``boolean = match(artist)`` used to filter matches + - class instance: eg Line2D. Only return artists of class type. - - class instance: eg Line2D. Only return artists of class type + If *include_self* is True (default), include self in the list to be + checked for a match. .. plot:: mpl_examples/pylab_examples/findobj_demo.py """ @@ -755,17 +759,18 @@ def matchfunc(x): elif callable(match): matchfunc = match else: - raise ValueError('match must be None, an matplotlib.artist.Artist subclass, or a callable') - + raise ValueError('match must be None, a matplotlib.artist.Artist subclass, or a callable') artists = [] for c in self.get_children(): if matchfunc(c): artists.append(c) - artists.extend([thisc for thisc in c.findobj(matchfunc) if matchfunc(thisc)]) + artists.extend([thisc for thisc in + c.findobj(matchfunc, include_self=False) + if matchfunc(thisc)]) - if matchfunc(self): + if include_self and matchfunc(self): artists.append(self) return artists From dcfdfe3a841eb1876da56021b7c5dbd737278b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Seppa=CC=88nen?= Date: Sun, 18 Sep 2011 23:07:13 +0300 Subject: [PATCH 145/214] Fix github url This is a quick patch to fix #478, not a future-proof solution. --- lib/matplotlib/cbook.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 58259ae85d8d..26203e0d5a2b 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -645,7 +645,7 @@ def get_sample_data(fname, asfileobj=True): Check the cachedirectory ~/.matplotlib/sample_data for a sample_data file. If it does not exist, fetch it with urllib from the mpl git repo - https://github.com/matplotlib/sample_data/raw/master + https://raw.github.com/matplotlib/sample_data/master and store it in the cachedir. @@ -676,7 +676,7 @@ def get_sample_data(fname, asfileobj=True): if myserver is None: configdir = matplotlib.get_configdir() cachedir = os.path.join(configdir, 'sample_data') - baseurl = 'https://github.com/matplotlib/sample_data/raw/master/' + baseurl = 'https://raw.github.com/matplotlib/sample_data/master/' try: myserver = _get_data_server(cachedir, baseurl) get_sample_data.myserver = myserver From 49c5d5ca039e16951d49d0bf2dc55f15a6cf9261 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 18 Sep 2011 13:24:01 -1000 Subject: [PATCH 146/214] cbook._putmask added to handle putmask deprecation in numpy > 1.6.x putmask is deprecated in favor of the new and more powerful copyto. --- lib/matplotlib/cbook.py | 17 +++++++++++++++++ lib/matplotlib/colors.py | 12 ++++++------ lib/matplotlib/quiver.py | 9 +++++---- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index 58259ae85d8d..20d340202366 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -1827,6 +1827,23 @@ def is_math_text(s): return even_dollars +# Numpy > 1.6.x deprecates putmask in favor of the new copyto. +# So long as we support versions 1.6.x and less, we need the +# following local version of putmask. We choose to make a +# local version of putmask rather than of copyto because the +# latter includes more functionality than the former. Therefore +# it is easy to make a local version that gives full putmask +# behavior, but duplicating the full copyto behavior would be +# more difficult. + +try: + np.copyto +except AttributeError: + _putmask = np.putmask +else: + def _putmask(a, mask, values): + return np.copyto(a, values, where=mask) + if __name__=='__main__': assert( allequal([1,1,1]) ) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 2ea65f153a84..bce6a3352d1b 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -516,7 +516,7 @@ def __call__(self, X, alpha=None, bytes=False): # masked values are substituted below; no need to fill them here if xa.dtype.char in np.typecodes['Float']: - np.putmask(xa, xa==1.0, 0.9999999) #Treat 1.0 as slightly less than 1. + cbook._putmask(xa, xa==1.0, 0.9999999) #Treat 1.0 as slightly less than 1. # The following clip is fast, and prevents possible # conversion of large positive values to negative integers. @@ -528,15 +528,15 @@ def __call__(self, X, alpha=None, bytes=False): # ensure that all 'under' values will still have negative # value after casting to int - np.putmask(xa, xa<0.0, -1) + cbook._putmask(xa, xa<0.0, -1) xa = xa.astype(int) # Set the over-range indices before the under-range; # otherwise the under-range values get converted to over-range. - np.putmask(xa, xa>self.N-1, self._i_over) - np.putmask(xa, xa<0, self._i_under) + cbook._putmask(xa, xa>self.N-1, self._i_over) + cbook._putmask(xa, xa<0, self._i_under) if mask_bad is not None: if mask_bad.shape == xa.shape: - np.putmask(xa, mask_bad, self._i_bad) + cbook._putmask(xa, mask_bad, self._i_bad) elif mask_bad: xa.fill(self._i_bad) if bytes: @@ -927,7 +927,7 @@ def __call__(self, value, clip=None): mask = (resdat <= 0) else: mask |= resdat <= 0 - np.putmask(resdat, mask, 1) + cbook._putmask(resdat, mask, 1) np.log(resdat, resdat) resdat -= np.log(vmin) resdat /= (np.log(vmax) - np.log(vmin)) diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py index 207add9a7e5e..7a507df17ac5 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -24,6 +24,7 @@ from matplotlib.artist import allow_rasterization from matplotlib import docstring import matplotlib.font_manager as font_manager +import matplotlib.cbook as cbook from matplotlib.cbook import delete_masked_points from matplotlib.patches import CirclePolygon import math @@ -624,8 +625,8 @@ def _h_arrows(self, length): Y0 = shrink * Y0[np.newaxis,:] short = np.repeat(length < minsh, 8, axis=1) # Now select X0, Y0 if short, otherwise X, Y - np.putmask(X, short, X0) - np.putmask(Y, short, Y0) + cbook._putmask(X, short, X0) + cbook._putmask(Y, short, Y0) if self.pivot[:3] == 'mid': X -= 0.5 * X[:,3, np.newaxis] elif self.pivot[:3] == 'tip': @@ -641,8 +642,8 @@ def _h_arrows(self, length): X1 = np.repeat(x1[np.newaxis, :], N, axis=0) Y1 = np.repeat(y1[np.newaxis, :], N, axis=0) tooshort = np.repeat(tooshort, 8, 1) - np.putmask(X, tooshort, X1) - np.putmask(Y, tooshort, Y1) + cbook._putmask(X, tooshort, X1) + cbook._putmask(Y, tooshort, Y1) # Mask handling is deferred to the caller, _make_verts. return X, Y From 012747b80d7c1d47141072e53876ba9541e8ba17 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Mon, 19 Sep 2011 10:58:08 +0900 Subject: [PATCH 147/214] axisartist: FormatterPrettyPrint turns off offset by default --- lib/mpl_toolkits/axisartist/grid_finder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpl_toolkits/axisartist/grid_finder.py b/lib/mpl_toolkits/axisartist/grid_finder.py index 5a693811ee66..53dd35d73dd9 100644 --- a/lib/mpl_toolkits/axisartist/grid_finder.py +++ b/lib/mpl_toolkits/axisartist/grid_finder.py @@ -300,7 +300,7 @@ def set_factor(self, f): class FormatterPrettyPrint(object): def __init__(self, useMathText=True): - self._fmt = mticker.ScalarFormatter(useMathText=useMathText) + self._fmt = mticker.ScalarFormatter(useMathText=useMathText, useOffset=False) self._fmt.create_dummy_axis() self._ignore_factor = True From 0a98984e0da9d0dfffd7c49031722d37ca512891 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 20 Sep 2011 07:38:33 -0400 Subject: [PATCH 148/214] Don't call "asarray" in symlog transformation functions. --- lib/matplotlib/scale.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index c8d20c21667b..5194503f5558 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -324,7 +324,6 @@ def __init__(self, base, linthresh): self._linadjust = (np.log(linthresh) / self._log_base) / linthresh def transform(self, a): - a = np.asarray(a) sign = np.sign(a) masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) log = sign * self.linthresh * (1 + ma.log(np.abs(masked) / self.linthresh)) @@ -352,7 +351,6 @@ def __init__(self, base, linthresh): self._linadjust = linthresh / (np.log(linthresh) / self._log_base) def transform(self, a): - a = np.asarray(a) sign = np.sign(a) masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) exp = sign * self.linthresh * ma.exp(sign * masked / self.linthresh - 1) @@ -393,7 +391,7 @@ def __init__(self, axis, **kwargs): assert base > 0.0 assert linthresh > 0.0 - + self.base = base self.linthresh = linthresh self.subs = subs From 453381b5ddc36c1137e4ae49d30cfe5172b9f28c Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Tue, 20 Sep 2011 20:43:14 +0900 Subject: [PATCH 149/214] axisartist: switch drawing order of ticks and ticklines --- lib/mpl_toolkits/axisartist/axis_artist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpl_toolkits/axisartist/axis_artist.py b/lib/mpl_toolkits/axisartist/axis_artist.py index 59239f6a0b01..373ea843e683 100644 --- a/lib/mpl_toolkits/axisartist/axis_artist.py +++ b/lib/mpl_toolkits/axisartist/axis_artist.py @@ -1552,10 +1552,10 @@ def draw(self, renderer): self.dpi_transform.clear().scale(dpi_cor, dpi_cor) - self._draw_line(renderer) - self._draw_ticks(renderer) + self._draw_line(renderer) + #self._draw_offsetText(renderer) self._draw_label(renderer) From 29b593f8296bda02eb63510c5c60a1365fa2ca43 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 20 Sep 2011 08:24:51 -0400 Subject: [PATCH 150/214] Fix images with "none" interpolation in the SVG backend. Inkscape doesn't like images with negative dimensions, so change to positive and adjust the offset accordingly. --- lib/matplotlib/backends/backend_svg.py | 5 +- .../test_image/interp_nearest_vs_none.svg | 164 +++++++++--------- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 661a7bcb221f..7ac7ce87b1c5 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -764,11 +764,12 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): width=str(w), height=str(h), attrib=attrib) else: + flipped = self._make_flip_transform(transform) attrib['transform'] = generate_transform( - [('matrix', transform.to_values())]) + [('matrix', flipped.to_values())]) self.writer.element( 'image', - x=str(x), y=str(y), width=str(dx), height=str(dy), + x=str(x), y=str(y+dy), width=str(dx), height=str(-dy), attrib=attrib) if url is not None: diff --git a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg index e80eb2436c91..87d5794c7b30 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg @@ -29,10 +29,10 @@ z " style="fill:#ffffff;"/> - +" y="-0.5"/> @@ -40,20 +40,20 @@ CJljvrVU8T+v6L0GhoZ/DP//JXv8BwBPvwlIEKcPcwAAAABJRU5ErkJggg== +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -131,20 +131,20 @@ z +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -161,20 +161,20 @@ L0 4" id="m5ee09eb6c1"/> +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -191,20 +191,20 @@ L0 4" id="m5ee09eb6c1"/> +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -237,20 +237,20 @@ z +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -269,20 +269,20 @@ L0 4" id="m5ee09eb6c1"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -300,20 +300,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -330,20 +330,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -360,20 +360,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -390,20 +390,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -670,20 +670,20 @@ EAwEgoFAMBAIBgLBQCAYCAQDgWAgEAwEX/HUCgtErBocAAAAAElFTkSuQmCC +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -701,20 +701,20 @@ L0 4" id="m5ee09eb6c1"/> +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -731,20 +731,20 @@ L0 4" id="m5ee09eb6c1"/> +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -761,20 +761,20 @@ L0 4" id="m5ee09eb6c1"/> +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -791,20 +791,20 @@ L0 4" id="m5ee09eb6c1"/> +L0 -4" id="m13b57186d2"/> - + +L0 4" id="m18a4b09ce5"/> - + @@ -823,20 +823,20 @@ L0 4" id="m5ee09eb6c1"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -854,20 +854,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -884,20 +884,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -914,20 +914,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + @@ -944,20 +944,20 @@ L-4 0" id="m02d8ef48b8"/> +L4 0" id="m5351898e3e"/> - + +L-4 0" id="md2ceb7ac7d"/> - + From 6f11254f9d7ca05672b59be5dacdbe335e93244f Mon Sep 17 00:00:00 2001 From: Kevin Davies Date: Tue, 20 Sep 2011 13:42:00 -0400 Subject: [PATCH 151/214] New entry in 'What's new', demo now accepts an argument (the example number) --- doc/users/whats_new.rst | 8 + examples/api/sankey_demo.py | 324 +++++++++++++++++++----------------- 2 files changed, 178 insertions(+), 154 deletions(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index e91d675a661b..2299b387f930 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -17,6 +17,14 @@ This page just covers the highlights -- for the full story, see the new in matplotlib-1.1 ===================== +Sankey Diagrams +--------- + +Kevin Davies has extended Yannick Copin's original Sankey example into a module +(:mod:`~matplotlib.sankey`) and provided new examples (:ref:`api-sankey_demo`). + +.. plot:: mpl_examples/api/sankey_demo.py 5 # Run the 5th example. + Animation --------- diff --git a/examples/api/sankey_demo.py b/examples/api/sankey_demo.py index 7fa5d33dfa41..e5707beff0e5 100644 --- a/examples/api/sankey_demo.py +++ b/examples/api/sankey_demo.py @@ -1,24 +1,36 @@ """Demonstrate the Sankey class. + +Accepts an optional argument indicating the example to produce (1 through 5). If +the argument isn't provided (or is 0), all the examples will be generated. """ import numpy as np import matplotlib.pyplot as plt +import sys from matplotlib.sankey import Sankey from itertools import cycle + +# Read the optional argument indentifying the example to run. +try: + example_num = int(sys.argv[1]) +except: + example_num = 0 + # Example 1 -- Mostly defaults # This demonstrates how to create a simple diagram by implicitly calling the # Sankey.add() method and by appending finish() to the call to the class. -Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], - labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], - orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() -plt.title("The default settings produce a diagram like this.") -# Notice: -# 1. Axes weren't provided when Sankey() was instantiated, so they were -# created automatically. -# 2. The scale argument wasn't necessary since the data was already -# normalized. -# 3. By default, the lengths of the paths are justified. +if example_num == 1 or example_num == 0: + Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], + labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], + orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() + plt.title("The default settings produce a diagram like this.") + # Notice: + # 1. Axes weren't provided when Sankey() was instantiated, so they were + # created automatically. + # 2. The scale argument wasn't necessary since the data was already + # normalized. + # 3. By default, the lengths of the paths are justified. # Example 2 # This demonstrates: @@ -31,162 +43,166 @@ # 7. Formatting the numbers in the path labels and the associated unit # 8. Changing the appearance of the patch and the labels after the figure is # created -fig = plt.figure() -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Flow Diagram of a Widget") -sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, - format='%.0f', unit='%') -sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], - labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', - 'Fifth', 'Hurray!'], - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], - pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, - 0.25], - patchlabel="Widget\nA", - alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() -diagrams = sankey.finish() -diagrams[0].patch.set_facecolor('#37c959') -diagrams[0].texts[-1].set_color('r') -diagrams[0].text.set_fontweight('bold') -# Notice: -# 1. Since the sum of the flows is nonzero, the width of the trunk isn't -# uniform. If verbose.level is helpful (in matplotlibrc), a message is -# given in the terminal window. -# 2. The second flow doesn't appear because its value is zero. Again, if -# verbose.level is helpful, a message is given in the terminal window. +if example_num == 2 or example_num == 0: + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Flow Diagram of a Widget") + sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, + format='%.0f', unit='%') + sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], + labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', + 'Fifth', 'Hurray!'], + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], + pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, + 0.25], + patchlabel="Widget\nA", + alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() + diagrams = sankey.finish() + diagrams[0].patch.set_facecolor('#37c959') + diagrams[0].texts[-1].set_color('r') + diagrams[0].text.set_fontweight('bold') + # Notice: + # 1. Since the sum of the flows is nonzero, the width of the trunk isn't + # uniform. If verbose.level is helpful (in matplotlibrc), a message is + # given in the terminal window. + # 2. The second flow doesn't appear because its value is zero. Again, if + # verbose.level is helpful, a message is given in the terminal window. # Example 3 # This demonstrates: # 1. Connecting two systems # 2. Turning off the labels of the quantities # 3. Adding a legend -fig = plt.figure() -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") -flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] -sankey = Sankey(ax=ax, unit=None) -sankey.add(flows=flows, label='one', - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) -sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', - orientations=[-1, -1, -1], prior=0, connect=(0, 0)) -diagrams = sankey.finish() -diagrams[-1].patch.set_hatch('/') -plt.legend(loc='best') -# Notice that only one connection is specified, but the systems form a circuit -# since: (1) the lengths of the paths are justified and (2) the orientation and -# ordering of the flows is mirrored. +if example_num == 3 or example_num == 0: + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") + flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] + sankey = Sankey(ax=ax, unit=None) + sankey.add(flows=flows, label='one', + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) + sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', + orientations=[-1, -1, -1], prior=0, connect=(0, 0)) + diagrams = sankey.finish() + diagrams[-1].patch.set_hatch('/') + plt.legend(loc='best') + # Notice that only one connection is specified, but the systems form a + # circuit since: (1) the lengths of the paths are justified and (2) the + # orientation and ordering of the flows is mirrored. # Example 4 # This tests a long chain of connections. -links_per_side = 6 -def side(sankey, n=1): - """Generate a side chain. - """ - prior = len(sankey.diagrams) - colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) - for i in range(0, 2*n, 2): - sankey.add(flows=[1, -1], orientations=[-1, -1], - patchlabel=str(prior+i), facecolor=colors.next(), - prior=prior+i-1, connect=(1, 0), alpha=0.5) - sankey.add(flows=[1, -1], orientations=[1, 1], - patchlabel=str(prior+i+1), facecolor=colors.next(), - prior=prior+i, connect=(1, 0), alpha=0.5) -def corner(sankey): - """Generate a corner link. - """ - prior = len(sankey.diagrams) +if example_num == 4 or example_num == 0: + links_per_side = 6 + def side(sankey, n=1): + """Generate a side chain. + """ + prior = len(sankey.diagrams) + colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) + for i in range(0, 2*n, 2): + sankey.add(flows=[1, -1], orientations=[-1, -1], + patchlabel=str(prior+i), facecolor=colors.next(), + prior=prior+i-1, connect=(1, 0), alpha=0.5) + sankey.add(flows=[1, -1], orientations=[1, 1], + patchlabel=str(prior+i+1), facecolor=colors.next(), + prior=prior+i, connect=(1, 0), alpha=0.5) + def corner(sankey): + """Generate a corner link. + """ + prior = len(sankey.diagrams) + sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel=str(prior), facecolor='k', + prior=prior-1, connect=(1, 0), alpha=0.5) + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Why would you want to do this?\n(But you could.)") + sankey = Sankey(ax=ax, unit=None) sankey.add(flows=[1, -1], orientations=[0, 1], - patchlabel=str(prior), facecolor='k', - prior=prior-1, connect=(1, 0), alpha=0.5) -fig = plt.figure() -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Why would you want to do this?\n(But you could.)") -sankey = Sankey(ax=ax, unit=None) -sankey.add(flows=[1, -1], orientations=[0, 1], - patchlabel="0", facecolor='k', - rotation=45) -side(sankey, n=links_per_side) -corner(sankey) -side(sankey, n=links_per_side) -corner(sankey) -side(sankey, n=links_per_side) -corner(sankey) -side(sankey, n=links_per_side) -sankey.finish() -# Notice: -# 1. The alignment doesn't drift significantly (if at all; with 16007 -# subdiagrams there is still closure). -# 2. The first diagram is rotated 45 deg, so all other diagrams are rotated -# accordingly. + patchlabel="0", facecolor='k', + rotation=45) + side(sankey, n=links_per_side) + corner(sankey) + side(sankey, n=links_per_side) + corner(sankey) + side(sankey, n=links_per_side) + corner(sankey) + side(sankey, n=links_per_side) + sankey.finish() + # Notice: + # 1. The alignment doesn't drift significantly (if at all; with 16007 + # subdiagrams there is still closure). + # 2. The first diagram is rotated 45 deg, so all other diagrams are rotated + # accordingly. # Example 5 # This is a practical example of a Rankine power cycle. -fig = plt.figure(figsize=(8, 12)) -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" - + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") -Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, - 142.361, 10.193, 10.210, 43.670, 44.312, - 68.631, 10.758, 10.758, 0.017, 0.642, - 232.121, 44.559, 100.613, 132.168] # MW -sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) -sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', - flows=[Hdot[13], Hdot[6], -Hdot[7]], - labels=['Shaft power', '', None], - pathlengths=[0.4, 0.883, 0.25], - orientations=[1, -1, 0]) -sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', - flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], - labels=[None, '', None, None], - pathlengths=[0.25, 0.25, 1.93, 0.25], - orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) -sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', - flows=[Hdot[14], Hdot[8], -Hdot[9]], - labels=['Shaft power', '', None], - pathlengths=[0.4, 0.25, 0.25], - orientations=[1, 0, 0], prior=1, connect=(3, 1)) -sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', - flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], - pathlengths=[0.25, 1.543, 0.25, 0.25], - labels=['', '', None, None], - orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) -sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, - flows=[Hdot[11], -Hdot[12]], - labels=['\n', None], - pathlengths=[1.0, 1.01], - orientations=[1, 1], prior=3, connect=(2, 0)) -sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', - flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], - labels=['Heat rate', '', '', None, None], - pathlengths=0.25, - orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) -sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', - flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], - labels=['', None, None, None], - pathlengths=[0.25, 0.153, 1.543, 0.25], - orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) -sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', - flows=[Hdot[2], -Hdot[2]], - labels=[None, None], - pathlengths=[0.725, 0.25], - orientations=[-1, 0], prior=6, connect=(3, 0)) -sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', - flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], - labels=[None, 'Shaft power', None, '', 'Shaft power'], - pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], - orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) -sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, - flows=[Hdot[5], -Hdot[18], -Hdot[6]], - labels=['', 'Heat rate', None], - pathlengths=[0.45, 0.25, 0.883], - orientations=[-1, 1, 0], prior=8, connect=(2, 0)) -diagrams = sankey.finish() -for diagram in diagrams: - diagram.text.set_fontweight('bold') - diagram.text.set_fontsize('10') - for text in diagram.texts: - text.set_fontsize('10') -# Notice that the explicit connections are handled automatically, but the -# implicit ones currently are not. The lengths of the paths and the trunks -# must be adjusted manually, and that is a bit tricky. +if example_num == 5 or example_num == 0: + fig = plt.figure(figsize=(8, 12)) + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" + + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") + Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, + 142.361, 10.193, 10.210, 43.670, 44.312, + 68.631, 10.758, 10.758, 0.017, 0.642, + 232.121, 44.559, 100.613, 132.168] # MW + sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) + sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', + flows=[Hdot[13], Hdot[6], -Hdot[7]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.883, 0.25], + orientations=[1, -1, 0]) + sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', + flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], + labels=[None, '', None, None], + pathlengths=[0.25, 0.25, 1.93, 0.25], + orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) + sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', + flows=[Hdot[14], Hdot[8], -Hdot[9]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.25, 0.25], + orientations=[1, 0, 0], prior=1, connect=(3, 1)) + sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', + flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], + pathlengths=[0.25, 1.543, 0.25, 0.25], + labels=['', '', None, None], + orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) + sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, + flows=[Hdot[11], -Hdot[12]], + labels=['\n', None], + pathlengths=[1.0, 1.01], + orientations=[1, 1], prior=3, connect=(2, 0)) + sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', + flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], + labels=['Heat rate', '', '', None, None], + pathlengths=0.25, + orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) + sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', + flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], + labels=['', None, None, None], + pathlengths=[0.25, 0.153, 1.543, 0.25], + orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) + sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', + flows=[Hdot[2], -Hdot[2]], + labels=[None, None], + pathlengths=[0.725, 0.25], + orientations=[-1, 0], prior=6, connect=(3, 0)) + sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', + flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], + labels=[None, 'Shaft power', None, '', 'Shaft power'], + pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], + orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) + sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, + flows=[Hdot[5], -Hdot[18], -Hdot[6]], + labels=['', 'Heat rate', None], + pathlengths=[0.45, 0.25, 0.883], + orientations=[-1, 1, 0], prior=8, connect=(2, 0)) + diagrams = sankey.finish() + for diagram in diagrams: + diagram.text.set_fontweight('bold') + diagram.text.set_fontsize('10') + for text in diagram.texts: + text.set_fontsize('10') + # Notice that the explicit connections are handled automatically, but the + # implicit ones currently are not. The lengths of the paths and the trunks + # must be adjusted manually, and that is a bit tricky. plt.show() From 79dce7cb68f81cbbb29e62d6b175088d7f04766c Mon Sep 17 00:00:00 2001 From: Kevin Davies Date: Tue, 20 Sep 2011 15:03:48 -0400 Subject: [PATCH 152/214] Split the demo into 3 files and made only 1 run from whats_new.rst --- doc/users/whats_new.rst | 8 +- examples/api/sankey_demo.py | 208 ---------------------------- examples/api/sankey_demo_basics.py | 80 +++++++++++ examples/api/sankey_demo_links.py | 51 +++++++ examples/api/sankey_demo_rankine.py | 79 +++++++++++ 5 files changed, 215 insertions(+), 211 deletions(-) delete mode 100644 examples/api/sankey_demo.py create mode 100644 examples/api/sankey_demo_basics.py create mode 100644 examples/api/sankey_demo_links.py create mode 100644 examples/api/sankey_demo_rankine.py diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 2299b387f930..eb663b63a69f 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -18,12 +18,14 @@ new in matplotlib-1.1 ===================== Sankey Diagrams ---------- +--------------- Kevin Davies has extended Yannick Copin's original Sankey example into a module -(:mod:`~matplotlib.sankey`) and provided new examples (:ref:`api-sankey_demo`). +(:mod:`~matplotlib.sankey`) and provided new examples +(:ref:`api-sankey_demo_basics`, :ref:`api-sankey_demo_links`, +:ref:`api-sankey_demo_rankine`). -.. plot:: mpl_examples/api/sankey_demo.py 5 # Run the 5th example. +.. plot:: mpl_examples/api/sankey_demo_rankine.py Animation --------- diff --git a/examples/api/sankey_demo.py b/examples/api/sankey_demo.py deleted file mode 100644 index e5707beff0e5..000000000000 --- a/examples/api/sankey_demo.py +++ /dev/null @@ -1,208 +0,0 @@ -"""Demonstrate the Sankey class. - -Accepts an optional argument indicating the example to produce (1 through 5). If -the argument isn't provided (or is 0), all the examples will be generated. -""" -import numpy as np -import matplotlib.pyplot as plt -import sys - -from matplotlib.sankey import Sankey -from itertools import cycle - - -# Read the optional argument indentifying the example to run. -try: - example_num = int(sys.argv[1]) -except: - example_num = 0 - -# Example 1 -- Mostly defaults -# This demonstrates how to create a simple diagram by implicitly calling the -# Sankey.add() method and by appending finish() to the call to the class. -if example_num == 1 or example_num == 0: - Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], - labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], - orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() - plt.title("The default settings produce a diagram like this.") - # Notice: - # 1. Axes weren't provided when Sankey() was instantiated, so they were - # created automatically. - # 2. The scale argument wasn't necessary since the data was already - # normalized. - # 3. By default, the lengths of the paths are justified. - -# Example 2 -# This demonstrates: -# 1. Setting one path longer than the others -# 2. Placing a label in the middle of the diagram -# 3. Using the the scale argument to normalize the flows -# 4. Implicitly passing keyword arguments to PathPatch() -# 5. Changing the angle of the arrow heads -# 6. Changing the offset between the tips of the paths and their labels -# 7. Formatting the numbers in the path labels and the associated unit -# 8. Changing the appearance of the patch and the labels after the figure is -# created -if example_num == 2 or example_num == 0: - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Flow Diagram of a Widget") - sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, - format='%.0f', unit='%') - sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], - labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', - 'Fifth', 'Hurray!'], - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], - pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, - 0.25], - patchlabel="Widget\nA", - alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() - diagrams = sankey.finish() - diagrams[0].patch.set_facecolor('#37c959') - diagrams[0].texts[-1].set_color('r') - diagrams[0].text.set_fontweight('bold') - # Notice: - # 1. Since the sum of the flows is nonzero, the width of the trunk isn't - # uniform. If verbose.level is helpful (in matplotlibrc), a message is - # given in the terminal window. - # 2. The second flow doesn't appear because its value is zero. Again, if - # verbose.level is helpful, a message is given in the terminal window. - -# Example 3 -# This demonstrates: -# 1. Connecting two systems -# 2. Turning off the labels of the quantities -# 3. Adding a legend -if example_num == 3 or example_num == 0: - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") - flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] - sankey = Sankey(ax=ax, unit=None) - sankey.add(flows=flows, label='one', - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) - sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', - orientations=[-1, -1, -1], prior=0, connect=(0, 0)) - diagrams = sankey.finish() - diagrams[-1].patch.set_hatch('/') - plt.legend(loc='best') - # Notice that only one connection is specified, but the systems form a - # circuit since: (1) the lengths of the paths are justified and (2) the - # orientation and ordering of the flows is mirrored. - -# Example 4 -# This tests a long chain of connections. -if example_num == 4 or example_num == 0: - links_per_side = 6 - def side(sankey, n=1): - """Generate a side chain. - """ - prior = len(sankey.diagrams) - colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) - for i in range(0, 2*n, 2): - sankey.add(flows=[1, -1], orientations=[-1, -1], - patchlabel=str(prior+i), facecolor=colors.next(), - prior=prior+i-1, connect=(1, 0), alpha=0.5) - sankey.add(flows=[1, -1], orientations=[1, 1], - patchlabel=str(prior+i+1), facecolor=colors.next(), - prior=prior+i, connect=(1, 0), alpha=0.5) - def corner(sankey): - """Generate a corner link. - """ - prior = len(sankey.diagrams) - sankey.add(flows=[1, -1], orientations=[0, 1], - patchlabel=str(prior), facecolor='k', - prior=prior-1, connect=(1, 0), alpha=0.5) - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Why would you want to do this?\n(But you could.)") - sankey = Sankey(ax=ax, unit=None) - sankey.add(flows=[1, -1], orientations=[0, 1], - patchlabel="0", facecolor='k', - rotation=45) - side(sankey, n=links_per_side) - corner(sankey) - side(sankey, n=links_per_side) - corner(sankey) - side(sankey, n=links_per_side) - corner(sankey) - side(sankey, n=links_per_side) - sankey.finish() - # Notice: - # 1. The alignment doesn't drift significantly (if at all; with 16007 - # subdiagrams there is still closure). - # 2. The first diagram is rotated 45 deg, so all other diagrams are rotated - # accordingly. - -# Example 5 -# This is a practical example of a Rankine power cycle. -if example_num == 5 or example_num == 0: - fig = plt.figure(figsize=(8, 12)) - ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], - title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" - + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") - Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, - 142.361, 10.193, 10.210, 43.670, 44.312, - 68.631, 10.758, 10.758, 0.017, 0.642, - 232.121, 44.559, 100.613, 132.168] # MW - sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) - sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', - flows=[Hdot[13], Hdot[6], -Hdot[7]], - labels=['Shaft power', '', None], - pathlengths=[0.4, 0.883, 0.25], - orientations=[1, -1, 0]) - sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', - flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], - labels=[None, '', None, None], - pathlengths=[0.25, 0.25, 1.93, 0.25], - orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) - sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', - flows=[Hdot[14], Hdot[8], -Hdot[9]], - labels=['Shaft power', '', None], - pathlengths=[0.4, 0.25, 0.25], - orientations=[1, 0, 0], prior=1, connect=(3, 1)) - sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', - flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], - pathlengths=[0.25, 1.543, 0.25, 0.25], - labels=['', '', None, None], - orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) - sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, - flows=[Hdot[11], -Hdot[12]], - labels=['\n', None], - pathlengths=[1.0, 1.01], - orientations=[1, 1], prior=3, connect=(2, 0)) - sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', - flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], - labels=['Heat rate', '', '', None, None], - pathlengths=0.25, - orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) - sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', - flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], - labels=['', None, None, None], - pathlengths=[0.25, 0.153, 1.543, 0.25], - orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) - sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', - flows=[Hdot[2], -Hdot[2]], - labels=[None, None], - pathlengths=[0.725, 0.25], - orientations=[-1, 0], prior=6, connect=(3, 0)) - sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', - flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], - labels=[None, 'Shaft power', None, '', 'Shaft power'], - pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], - orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) - sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, - flows=[Hdot[5], -Hdot[18], -Hdot[6]], - labels=['', 'Heat rate', None], - pathlengths=[0.45, 0.25, 0.883], - orientations=[-1, 1, 0], prior=8, connect=(2, 0)) - diagrams = sankey.finish() - for diagram in diagrams: - diagram.text.set_fontweight('bold') - diagram.text.set_fontsize('10') - for text in diagram.texts: - text.set_fontsize('10') - # Notice that the explicit connections are handled automatically, but the - # implicit ones currently are not. The lengths of the paths and the trunks - # must be adjusted manually, and that is a bit tricky. - -plt.show() diff --git a/examples/api/sankey_demo_basics.py b/examples/api/sankey_demo_basics.py new file mode 100644 index 000000000000..bc59329f44c7 --- /dev/null +++ b/examples/api/sankey_demo_basics.py @@ -0,0 +1,80 @@ +"""Demonstrate the Sankey class by producing three basic diagrams. +""" +import numpy as np +import matplotlib.pyplot as plt +import sys + +from matplotlib.sankey import Sankey +from itertools import cycle + + +# Example 1 -- Mostly defaults +# This demonstrates how to create a simple diagram by implicitly calling the +# Sankey.add() method and by appending finish() to the call to the class. +Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], + labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], + orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() +plt.title("The default settings produce a diagram like this.") +# Notice: +# 1. Axes weren't provided when Sankey() was instantiated, so they were +# created automatically. +# 2. The scale argument wasn't necessary since the data was already +# normalized. +# 3. By default, the lengths of the paths are justified. + +# Example 2 +# This demonstrates: +# 1. Setting one path longer than the others +# 2. Placing a label in the middle of the diagram +# 3. Using the the scale argument to normalize the flows +# 4. Implicitly passing keyword arguments to PathPatch() +# 5. Changing the angle of the arrow heads +# 6. Changing the offset between the tips of the paths and their labels +# 7. Formatting the numbers in the path labels and the associated unit +# 8. Changing the appearance of the patch and the labels after the figure is +# created +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Flow Diagram of a Widget") +sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, + format='%.0f', unit='%') +sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], + labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', + 'Fifth', 'Hurray!'], + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], + pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, + 0.25], + patchlabel="Widget\nA", + alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() +diagrams = sankey.finish() +diagrams[0].patch.set_facecolor('#37c959') +diagrams[0].texts[-1].set_color('r') +diagrams[0].text.set_fontweight('bold') +# Notice: +# 1. Since the sum of the flows is nonzero, the width of the trunk isn't +# uniform. If verbose.level is helpful (in matplotlibrc), a message is +# given in the terminal window. +# 2. The second flow doesn't appear because its value is zero. Again, if +# verbose.level is helpful, a message is given in the terminal window. + +# Example 3 +# This demonstrates: +# 1. Connecting two systems +# 2. Turning off the labels of the quantities +# 3. Adding a legend +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") +flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] +sankey = Sankey(ax=ax, unit=None) +sankey.add(flows=flows, label='one', + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) +sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', + orientations=[-1, -1, -1], prior=0, connect=(0, 0)) +diagrams = sankey.finish() +diagrams[-1].patch.set_hatch('/') +plt.legend(loc='best') +# Notice that only one connection is specified, but the systems form a +# circuit since: (1) the lengths of the paths are justified and (2) the +# orientation and ordering of the flows is mirrored. + +plt.show() diff --git a/examples/api/sankey_demo_links.py b/examples/api/sankey_demo_links.py new file mode 100644 index 000000000000..b91985519874 --- /dev/null +++ b/examples/api/sankey_demo_links.py @@ -0,0 +1,51 @@ +"""Demonstrate the Sankey class by producing a long chain of connections. +""" +import numpy as np +import matplotlib.pyplot as plt +import sys + +from matplotlib.sankey import Sankey +from itertools import cycle + +links_per_side = 6 +def side(sankey, n=1): + """Generate a side chain. + """ + prior = len(sankey.diagrams) + colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) + for i in range(0, 2*n, 2): + sankey.add(flows=[1, -1], orientations=[-1, -1], + patchlabel=str(prior+i), facecolor=colors.next(), + prior=prior+i-1, connect=(1, 0), alpha=0.5) + sankey.add(flows=[1, -1], orientations=[1, 1], + patchlabel=str(prior+i+1), facecolor=colors.next(), + prior=prior+i, connect=(1, 0), alpha=0.5) +def corner(sankey): + """Generate a corner link. + """ + prior = len(sankey.diagrams) + sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel=str(prior), facecolor='k', + prior=prior-1, connect=(1, 0), alpha=0.5) +fig = plt.figure() +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Why would you want to do this?\n(But you could.)") +sankey = Sankey(ax=ax, unit=None) +sankey.add(flows=[1, -1], orientations=[0, 1], + patchlabel="0", facecolor='k', + rotation=45) +side(sankey, n=links_per_side) +corner(sankey) +side(sankey, n=links_per_side) +corner(sankey) +side(sankey, n=links_per_side) +corner(sankey) +side(sankey, n=links_per_side) +sankey.finish() +# Notice: +# 1. The alignment doesn't drift significantly (if at all; with 16007 +# subdiagrams there is still closure). +# 2. The first diagram is rotated 45 deg, so all other diagrams are rotated +# accordingly. + +plt.show() diff --git a/examples/api/sankey_demo_rankine.py b/examples/api/sankey_demo_rankine.py new file mode 100644 index 000000000000..ae12582c1d39 --- /dev/null +++ b/examples/api/sankey_demo_rankine.py @@ -0,0 +1,79 @@ +"""Demonstrate the Sankey class with a practicle example of a Rankine power cycle. +""" +import numpy as np +import matplotlib.pyplot as plt +import sys + +from matplotlib.sankey import Sankey +from itertools import cycle + +fig = plt.figure(figsize=(8, 12)) +ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], + title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" + + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") +Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, + 142.361, 10.193, 10.210, 43.670, 44.312, + 68.631, 10.758, 10.758, 0.017, 0.642, + 232.121, 44.559, 100.613, 132.168] # MW +sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) +sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', + flows=[Hdot[13], Hdot[6], -Hdot[7]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.883, 0.25], + orientations=[1, -1, 0]) +sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', + flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], + labels=[None, '', None, None], + pathlengths=[0.25, 0.25, 1.93, 0.25], + orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) +sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', + flows=[Hdot[14], Hdot[8], -Hdot[9]], + labels=['Shaft power', '', None], + pathlengths=[0.4, 0.25, 0.25], + orientations=[1, 0, 0], prior=1, connect=(3, 1)) +sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', + flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], + pathlengths=[0.25, 1.543, 0.25, 0.25], + labels=['', '', None, None], + orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) +sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, + flows=[Hdot[11], -Hdot[12]], + labels=['\n', None], + pathlengths=[1.0, 1.01], + orientations=[1, 1], prior=3, connect=(2, 0)) +sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', + flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], + labels=['Heat rate', '', '', None, None], + pathlengths=0.25, + orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) +sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', + flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], + labels=['', None, None, None], + pathlengths=[0.25, 0.153, 1.543, 0.25], + orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) +sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', + flows=[Hdot[2], -Hdot[2]], + labels=[None, None], + pathlengths=[0.725, 0.25], + orientations=[-1, 0], prior=6, connect=(3, 0)) +sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', + flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], + labels=[None, 'Shaft power', None, '', 'Shaft power'], + pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], + orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) +sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, + flows=[Hdot[5], -Hdot[18], -Hdot[6]], + labels=['', 'Heat rate', None], + pathlengths=[0.45, 0.25, 0.883], + orientations=[-1, 1, 0], prior=8, connect=(2, 0)) +diagrams = sankey.finish() +for diagram in diagrams: + diagram.text.set_fontweight('bold') + diagram.text.set_fontsize('10') + for text in diagram.texts: + text.set_fontsize('10') +# Notice that the explicit connections are handled automatically, but the +# implicit ones currently are not. The lengths of the paths and the trunks +# must be adjusted manually, and that is a bit tricky. + +plt.show() From 39c7b5517e224e4c4122d0487290bfe92a63c078 Mon Sep 17 00:00:00 2001 From: Kevin Davies Date: Tue, 20 Sep 2011 15:15:33 -0400 Subject: [PATCH 153/214] Removed unnecessary imports --- examples/api/sankey_demo_basics.py | 2 -- examples/api/sankey_demo_links.py | 3 +-- examples/api/sankey_demo_rankine.py | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/api/sankey_demo_basics.py b/examples/api/sankey_demo_basics.py index bc59329f44c7..2e84b51fee49 100644 --- a/examples/api/sankey_demo_basics.py +++ b/examples/api/sankey_demo_basics.py @@ -2,10 +2,8 @@ """ import numpy as np import matplotlib.pyplot as plt -import sys from matplotlib.sankey import Sankey -from itertools import cycle # Example 1 -- Mostly defaults diff --git a/examples/api/sankey_demo_links.py b/examples/api/sankey_demo_links.py index b91985519874..b7064c7030c4 100644 --- a/examples/api/sankey_demo_links.py +++ b/examples/api/sankey_demo_links.py @@ -1,8 +1,7 @@ -"""Demonstrate the Sankey class by producing a long chain of connections. +"""Demonstrate/test the Sankey class by producing a long chain of connections. """ import numpy as np import matplotlib.pyplot as plt -import sys from matplotlib.sankey import Sankey from itertools import cycle diff --git a/examples/api/sankey_demo_rankine.py b/examples/api/sankey_demo_rankine.py index ae12582c1d39..13e5a5ffbf7d 100644 --- a/examples/api/sankey_demo_rankine.py +++ b/examples/api/sankey_demo_rankine.py @@ -2,10 +2,8 @@ """ import numpy as np import matplotlib.pyplot as plt -import sys from matplotlib.sankey import Sankey -from itertools import cycle fig = plt.figure(figsize=(8, 12)) ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], From 1c988130ae354e9bdc8225cf46c5189a18648f37 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Tue, 20 Sep 2011 16:05:57 -0500 Subject: [PATCH 154/214] Documentation cleanup and expansion in the FAQs. --- doc/faq/howto_faq.rst | 127 ++++++++++++++------------- doc/faq/installing_faq.rst | 150 ++++++++++++++++++++------------ doc/faq/troubleshooting_faq.rst | 8 +- 3 files changed, 163 insertions(+), 122 deletions(-) diff --git a/doc/faq/howto_faq.rst b/doc/faq/howto_faq.rst index 8a3d3d4dd8ad..c3a4d75b7fba 100644 --- a/doc/faq/howto_faq.rst +++ b/doc/faq/howto_faq.rst @@ -1,8 +1,8 @@ .. _howto-faq: -***** -Howto -***** +****** +How-To +****** .. contents:: :backlinks: none @@ -45,12 +45,14 @@ Save transparent figures ---------------------------------- The :meth:`~matplotlib.pyplot.savefig` command has a keyword argument -*transparent* which, if True, will make the figure and axes +*transparent* which, if 'True', will make the figure and axes backgrounds transparent when saving, but will not affect the displayed -image on the screen. If you need finer grained control, eg you do not -want full transparency or you to affect the screen displayed version -as well, you can set the alpha properties directly. The figure has a -:class:`matplotlib.patches.Rectangle` instance called *patch* +image on the screen. + +If you need finer grained control, eg you do not want full transparency +or you want to affect the screen displayed version as well, you can set +the alpha properties directly. The figure has a +:class:`~matplotlib.patches.Rectangle` instance called *patch* and the axes has a Rectangle instance called *patch*. You can set any property on them directly (*facecolor*, *edgecolor*, *linewidth*, *linestyle*, *alpha*). Eg:: @@ -85,7 +87,7 @@ You can give the :class:`~matplotlib.backends.backend_pdf.PdfPages` object to :func:`~matplotlib.pyplot.savefig`, but you have to specify the format:: - savefig(pp, format='pdf') + plt.savefig(pp, format='pdf') An easier way is to call :meth:`PdfPages.savefig `:: @@ -138,7 +140,7 @@ The other parameters you can configure are, with their defaults If you want additional control, you can create an :class:`~matplotlib.axes.Axes` using the :func:`~matplotlib.pyplot.axes` command (or equivalently the figure -:meth:`matplotlib.figure.Figure.add_axes` method), which allows you to +:meth:`~matplotlib.figure.Figure.add_axes` method), which allows you to specify the location explicitly:: ax = fig.add_axes([left, bottom, width, height]) @@ -149,7 +151,15 @@ where all values are in fractional (0 to 1) coordinates. See .. _howto-auto-adjust: Automatically make room for tick labels ----------------------------------------------------- +--------------------------------------- + +.. note:: + This is now easier to handle than ever before. + Calling :func:`~matplotlib.pyplot.tight_layout` can fix many common + layout issues. See the :ref:`plotting-guide-tight-layout`. + + The information below is kept here in case it is useful for other + purposes. In most use cases, it is enough to simply change the subplots adjust parameters as described in :ref:`howto-subplots-adjust`. But in some @@ -157,18 +167,18 @@ cases, you don't know ahead of time what your tick labels will be, or how large they will be (data and labels outside your control may be being fed into your graphing application), and you may need to automatically adjust your subplot parameters based on the size of the -tick labels. Any :class:`matplotlib.text.Text` instance can report +tick labels. Any :class:`~matplotlib.text.Text` instance can report its extent in window coordinates (a negative x coordinate is outside the window), but there is a rub. -The :class:`matplotlib.backend_bases.RendererBase` instance, which is +The :class:`~matplotlib.backend_bases.RendererBase` instance, which is used to calculate the text size, is not known until the figure is -drawn (:meth:`matplotlib.figure.Figure.draw`). After the window is +drawn (:meth:`~matplotlib.figure.Figure.draw`). After the window is drawn and the text instance knows its renderer, you can call -:meth:`matplotlib.text.Text.get_window_extent`. One way to solve +:meth:`~matplotlib.text.Text.get_window_extent`. One way to solve this chicken and egg problem is to wait until the figure is draw by connecting -(:meth:`matplotlib.backend_bases.FigureCanvasBase.mpl_connect`) to the +(:meth:`~matplotlib.backend_bases.FigureCanvasBase.mpl_connect`) to the "on_draw" signal (:class:`~matplotlib.backend_bases.DrawEvent`) and get the window extent there, and then do something with it, eg move the left of the canvas over; see :ref:`event-handling-tutorial`. @@ -183,7 +193,7 @@ over so that the tick labels fit in the figure .. _howto-ticks: Configure the tick linewidths ---------------------------------------- +----------------------------- In matplotlib, the ticks are *markers*. All :class:`~matplotlib.lines.Line2D` objects support a line (solid, @@ -209,7 +219,7 @@ are ``markerfacecolor``, ``markeredgecolor``, ``markeredgewidth``, .. _howto-align-label: Align my ylabels across multiple subplots ---------------------------------------------------- +----------------------------------------- If you have multiple subplots over one another, and the y data have different scales, you can often get ylabels that do not align @@ -226,7 +236,7 @@ setting in the right subplots. .. _date-index-plots: Skip dates where there is no data -------------------------------------- +--------------------------------- When plotting time series, eg financial time series, one often wants to leave out days on which there is no data, eg weekends. By passing @@ -263,9 +273,9 @@ to achieve the desired plot:: .. _point-in-poly: Test whether a point is inside a polygon -------------------------------------------- +---------------------------------------- -The :mod:`matplotlib.nxutils` provides two high performance methods: +The :mod:`~matplotlib.nxutils` provides two high-performance methods: for a single point use :func:`~matplotlib.nxutils.pnpoly` and for an array of points use :func:`~matplotlib.nxutils.points_inside_poly`. For a discussion of the implementation see `pnpoly @@ -310,12 +320,12 @@ For a discussion of the implementation see `pnpoly .. _howto-set-zorder: Control the depth of plot elements ---------------------------------------- +---------------------------------- Within an axes, the order that the various lines, markers, text, collections, etc appear is determined by the -:meth:`matplotlib.artist.Artist.set_zorder` property. The default +:meth:`~matplotlib.artist.Artist.set_zorder` property. The default order is patches, lines, text, with collections of lines and collections of patches appearing at the same level as regular lines and patches, respectively:: @@ -327,15 +337,15 @@ and patches, respectively:: See :ref:`pylab_examples-zorder_demo` for a complete example. You can also use the Axes property -:meth:`matplotlib.axes.Axes.set_axisbelow` to control whether the grid +:meth:`~matplotlib.axes.Axes.set_axisbelow` to control whether the grid lines are placed above or below your other plot elements. .. _howto-axis-equal: Make the aspect ratio for plots equal -------------------------------------------- +------------------------------------- -The Axes property :meth:`matplotlib.axes.Axes.set_aspect` controls the +The Axes property :meth:`~matplotlib.axes.Axes.set_aspect` controls the aspect ratio of the axes. You can set it to be 'auto', 'equal', or some ratio which controls the ratio:: @@ -351,8 +361,7 @@ some ratio which controls the ratio:: .. _howto-movie: Make a movie ------------------------------------------------ - +------------ If you want to take an animated plot and turn it into a movie, the best approach is to save a series of image files (eg PNG) and use an @@ -392,13 +401,14 @@ a movie, and then cleans up:: .. htmlonly:: - Josh Lifton provided this example :ref:`animation-movie_demo`, which is possibly dated since it was written in 2004. + Josh Lifton provided this example :ref:`old_animation-movie_demo`, which + is possibly dated since it was written in 2004. .. _howto-twoscale: Multiple y-axis scales -------------------------------- +---------------------- A frequent request is to have two scales for the left and right y-axis, which is possible using :func:`~matplotlib.pyplot.twinx` (more @@ -412,8 +422,9 @@ The approach uses :func:`~matplotlib.pyplot.twinx` (and its sister turning the axes rectangular frame off on the 2nd axes to keep it from obscuring the first, and manually setting the tick locs and labels as desired. You can use separate matplotlib.ticker formatters and -locators as desired because the two axes are independent:: +locators as desired because the two axes are independent. +.. plot:: import numpy as np import matplotlib.pyplot as plt @@ -438,8 +449,8 @@ locators as desired because the two axes are independent:: .. _howto-batch: -Generate images without having a window popup --------------------------------------------------- +Generate images without having a window appear +---------------------------------------------- The easiest way to do this is use a non-interactive backend (see :ref:`what-is-a-backend`) such as Agg (for PNGs), PDF, SVG or PS. In @@ -455,9 +466,8 @@ pyplot:: .. seealso:: - :ref:`howto-webapp` - For information about running matplotlib inside of a web - application. + :ref:`howto-webapp` for information about running matplotlib inside + of a web application. .. _howto-show: @@ -468,12 +478,12 @@ When you want to view your plots on your display, the user interface backend will need to start the GUI mainloop. This is what :func:`~matplotlib.pyplot.show` does. It tells matplotlib to raise all of the figure windows created so far and start -the mainloop. Because this mainloop is blocking (i.e., script execution is -paused), you should only call this once per script, at the end. Script -execution is resumed after the last window is closed. Therefore, if you are -using matplotlib to generate only images and do not want a user interface -window, you do not need to call ``show`` (see :ref:`howto-batch` and -:ref:`what-is-a-backend`). +the mainloop. Because this mainloop is blocking by default (i.e., script +execution is paused), you should only call this once per script, at the end. +Script execution is resumed after the last window is closed. Therefore, if +you are using matplotlib to generate only images and do not want a user +interface window, you do not need to call ``show`` (see :ref:`howto-batch` +and :ref:`what-is-a-backend`). .. note:: Because closing a figure window invokes the destruction of its plotting @@ -518,7 +528,6 @@ important for complex figures that take some time to draw. you're all done issuing commands and you want to draw the figure now. .. note:: - :func:`~matplotlib.pyplot.show` should typically only be called at most once per script and it should be the last line of your script. At that point, the GUI takes control of the interpreter. If you want @@ -549,12 +558,12 @@ though we have made significant progress towards supporting blocking events. .. _howto-contribute: Contributing: howto -===================== +=================== .. _how-to-submit-patch: Submit a patch ------------------ +-------------- See :ref:`making-patches` for information on how to make a patch with git. @@ -563,10 +572,10 @@ patch in words -- what was broken before and how you fixed it. Also, even if your patch is particularly simple, just a few lines or a single function replacement, we encourage people to submit git diffs against HEAD of the branch they are patching. It just makes life -simpler for us, since we (fortunately) get a lot of contributions, and +easier for us, since we (fortunately) get a lot of contributions, and want to receive them in a standard format. If possible, for any non-trivial change, please include a complete, free-standing example -that the developers can run unmodified which shows the undesired +that the developers can run unmodified which shows the undesired behavior pre-patch and the desired behavior post-patch, with a clear verbal description of what to look for. A developer may have written the function you are working on years ago, and may no @@ -588,7 +597,7 @@ your patch abides by our coding conventions .. _how-to-contribute-docs: Contribute to matplotlib documentation ------------------------------------------ +-------------------------------------- matplotlib is a big library, which is used in many ways, and the documentation has only scratched the surface of everything it can @@ -637,7 +646,7 @@ Looking for something to do? Search for `TODO <../search.html?q=todo>`_. .. _howto-webapp: Matplotlib in a web application server -==================================================== +====================================== Many users report initial problems trying to use maptlotlib in web application servers, because by default matplotlib ships configured to @@ -681,7 +690,7 @@ or by saving to a file handle:: import sys fig.savefig(sys.stdout) -Here is an example using the Python Imaging Library PIL. First the figure +Here is an example using the Python Imaging Library (PIL). First, the figure is saved to a StringIO object which is then fed to PIL for further processing:: @@ -693,17 +702,17 @@ processing:: matplotlib with apache ------------------------------------- +---------------------- TODO; see :ref:`how-to-contribute-docs`. matplotlib with django ------------------------------------- +---------------------- TODO; see :ref:`how-to-contribute-docs`. matplotlib with zope ----------------------------------- +-------------------- TODO; see :ref:`how-to-contribute-docs`. @@ -724,7 +733,7 @@ to these efforts that would be great. .. _how-to-search-examples: Search examples -========================================= +=============== The nearly 300 code :ref:`examples-index` included with the matplotlib source distribution are full-text searchable from the :ref:`search` @@ -733,19 +742,15 @@ page, but sometimes when you search, you get a lot of results from the in if you just want to find a complete, free-standing, working piece of example code. To facilitate example searches, we have tagged every code example page with the keyword ``codex`` for *code example* which -shouldn't appear anywhere else on this site except in the FAQ and in -every example. So if you want to search for an example that uses an +shouldn't appear anywhere else on this site except in the FAQ. +So if you want to search for an example that uses an ellipse, :ref:`search` for ``codex ellipse``. - - - - .. _how-to-cite-mpl: Cite Matplotlib -================= +=============== If you want to refer to matplotlib in a publication, you can use "Matplotlib: A 2D Graphics Environment" by J. D. Hunter In Computing in Science & diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst index 52a3cf665c42..26d843a8fd98 100644 --- a/doc/faq/installing_faq.rst +++ b/doc/faq/installing_faq.rst @@ -1,8 +1,8 @@ .. _installing-faq: -***************** - Installation FAQ -***************** +************* + Installation +************* .. contents:: @@ -10,12 +10,12 @@ Report a compilation problem -====================================== +============================ See :ref:`reporting-problems`. -matplotlib compiled fine, but nothing shows up with plot -========================================================== +matplotlib compiled fine, but nothing shows up when I use it +============================================================ The first thing to try is a :ref:`clean install ` and see if that helps. If not, the best way to test your install is by running a script, @@ -23,7 +23,7 @@ rather than working interactively from a python shell or an integrated development environment such as :program:`IDLE` which add additional complexities. Open up a UNIX shell or a DOS command prompt and cd into a directory containing a minimal example in a file. Something like -:file:`simple_plot.py`, or for example:: +:file:`simple_plot.py` for example:: from pylab import * plot([1,2,3]) @@ -43,10 +43,16 @@ If you are still having trouble, see :ref:`reporting-problems`. .. _clean-install: -Cleanly rebuild and reinstall everything -======================================== +How to completely remove matplotlib +=================================== -The steps depend on your platform and installation method. +Occasionally, problems with matplotlib can be solved with a clean +installation of the package. + +The process for removing an installation of matplotlib depends on how +matplotlib was originally installed on your system. Follow the steps +below that goes with your original installation method to cleanly +remove matplotlib from your system. Easy Install ------------ @@ -56,7 +62,7 @@ Easy Install 2. Run:: - easy_install -m PackageName + easy_install -m matplotlib 3. Delete any .egg files or directories from your :ref:`installation @@ -86,16 +92,18 @@ install directory. To cleanly rebuild: 1. Delete the caches from your :ref:`.matplotlib configuration directory `. -2. Delete the ``build`` directory in the source tree +2. Delete the ``build`` directory in the source tree. -3. Delete any matplotlib directories or eggs from your `installation directory - ` +3. Delete any matplotlib directories or eggs from your :ref:`installation + directory `. +How to Install +============== .. _install-from-git: -Install from git -================ +Source install from git +----------------------- Clone the main source using one of:: @@ -145,22 +153,43 @@ There is more information on :ref:`using git ` in the developer docs. -OS-X questions -============== +Linux Notes +=========== + +Because most Linux distributions use some sort of package manager, +we do not provide a pre-built binary for the Linux platform. +Instead, we recommend that you use the "Add Software" method for +your system to install matplotlib. This will guarantee that everything +that is needed for matplotlib will be installed as well. + +If, for some reason, you can not use the package manager, Linux usually +comes with at least a basic build system. Follow the :ref:`instructions +` found above for how to build and install matplotlib. + + +OS-X Notes +========== .. _which-python-for-osx: Which python for OS X? ---------------------- -Apple ships with its own python, many users have had trouble -with it so there are alternatives. If it is feasible for you, we -recommend the enthought python distribution `EPD -`_ for OS X (which comes -with matplotlib and much more) or the +Apple ships with its own python, and many users have had trouble +with it. There are several alternative versions of python that +can be used. If it is feasible, we recommend that you use the enthought +python distribution `EPD `_ +for OS X (which comes with matplotlib and much more). Also available is `MacPython `_ or the -official OS X version from `python.org -`_. +official OS X version from `python.org `_. + +.. note:: + Before installing any of the binary packages, be sure that all of the + packages were compiled for the same version of python. + Often, the download site for NumPy and matplotlib will display a + supposed 'current' version of the package, but you may need to choose + a different package from the full list that was built for your + combination of python and OSX. .. _install_osx_binaries: @@ -170,21 +199,21 @@ Installing OSX binaries If you want to install matplotlib from one of the binary installers we build, you have two choices: a mpkg installer, which is a typical -Installer.app, or an binary OSX egg, which you can install via -setuptools easy_install. +Installer.app, or a binary OSX egg, which you can install via +setuptools' easy_install. The mkpg installer will have a "zip" extension, and will have a name -like file:`matplotlib-0.99.0.rc1-py2.5-macosx10.5_mpkg.zip` depending on -the python, matplotlib, and OSX versions. You need to unzip this file -using either the "unzip" command on OSX, or simply double clicking on -it to run StuffIt Expander. When you double click on the resultant -mpkd directory, which will have a name like -file:`matplotlib-0.99.0.rc1-py2.5-macosx10.5.mpkg`, it will run the -Installer.app, prompt you for a password if you need system wide +like :file:`matplotlib-0.99.0.rc1-py2.5-macosx10.5_mpkg.zip`. +The name of the installer depends on which versions of python, matplotlib, +and OSX it was built for. You need to unzip this file using either the +"unzip" command, or simply double clicking on the it. Then when you +double-click on the resulting mpkd, which will have a name like +:file:`matplotlib-0.99.0.rc1-py2.5-macosx10.5.mpkg`, it will run the +Installer.app, prompt you for a password if you need system-wide installation privileges, and install to a directory like -file:`/Library/Python/2.5/site-packages/`, again depending on your -python version. This directory may not be in your python path, so you -should test your installation with:: +:file:`/Library/Python/2.5/site-packages/` (exact path depends on your +python version). This directory may not be in your python 'path' variable, +so you should test your installation with:: > python -c 'import matplotlib; print matplotlib.__version__, matplotlib.__file__' @@ -203,7 +232,7 @@ See also ref:`environment-variables`. .. _easy-install-osx-egg: easy_install from egg ------------------------------- +--------------------- You can also use the eggs we build for OSX (see the `installation instructions @@ -213,15 +242,20 @@ can try:: > easy_install matplotlib -which should grab the latest egg from the sourceforge site, but the -naming conventions for OSX eggs appear to be broken (see below) so -there is no guarantee the right egg will be found. We recommend you -download the latest egg from our `download site +which should grab the latest egg from the sourceforge site, but sometimes +the naming conventions for OSX eggs can be broken (see below). +Therefore, there is no guarantee the right egg will be found. We recommend +you download the latest egg from our `download site `_ directly to your -harddrive, and manually install it with +harddrive, and manually install it, eg:: > easy_install --install-dir=~/dev/lib/python2.5/site-packages/ matplotlib-0.99.0.rc1-py2.5-macosx-10.5-i386.egg +Naming convention issues +^^^^^^^^^^^^^^^^^^^^^^^^ +.. note:: + This should no longer be an issue. If it is, please + report it to the mailing list. Some users have reported problems with the egg for 0.98 from the matplotlib download site, with ``easy_install``, getting an error:: @@ -267,14 +301,14 @@ Comment out the line containing the name of the directory in which the previous version of MPL was installed (Looks something like ``./matplotlib-0.98.5.2n2-py2.5-macosx-10.3-fat.egg``). -3. Save the following as a shell script , for example +3. Save the following as a shell script, for example ``./install-matplotlib-epd-osx.sh``:: NAME=matplotlib - VERSION=v1.0.x + VERSION=v1.1.x PREFIX=$HOME #branch="release" - branch="trunk" + branch="master" git clone git://github.com/matplotlib/matplotlib.git cd matplotlib if [ $branch = "release" ] @@ -295,17 +329,17 @@ Run this script (for example ``sh ./install-matplotlib-epd-osx.sh``) in the directory in which you want the source code to be placed, or simply type the commands in the terminal command line. This script sets some local variable (CFLAGS, LDFLAGS, PKG_CONFIG_PATH, ARCHFLAGS), removes previous installations, -checks out the source from github, builds and installs it. The backend seems +checks out the source from github, builds and installs it. The backend should to be set to MacOSX. -Windows questions -================= +Windows Notes +============= .. _windows-installers: -Binary installers for windows ----------------------------------------------- +Binary installers for Windows +----------------------------- If you have already installed python, you can use one of the matplotlib binary installers for windows -- you can get these from the @@ -315,13 +349,15 @@ site. Choose the files that match your version of python (eg ``py2.5`` if you installed Python 2.5) which have the ``exe`` extension. If you haven't already installed python, you can get the official version from the `python web site -`_. There are also two packaged -distributions of python that come preloaded with matplotlib and many -other tools like ipython, numpy, scipy, vtk and user interface -toolkits. These packages are quite large because they come with so -much, but you get everything with a single click installer. +`_. + +There are also two packaged distributions of python that come +preloaded with matplotlib and many other tools like ipython, numpy, +scipy, vtk and user interface toolkits. These packages are quite +large because they come with so much, but you get everything with +a single click installer. -* the enthought python distribution `EPD +* The Enthought Python Distribution `EPD `_ * `python (x, y) `_ diff --git a/doc/faq/troubleshooting_faq.rst b/doc/faq/troubleshooting_faq.rst index a4ae3b00e9be..ecdb6cb2e396 100644 --- a/doc/faq/troubleshooting_faq.rst +++ b/doc/faq/troubleshooting_faq.rst @@ -10,7 +10,7 @@ Troubleshooting .. _matplotlib-version: Obtaining matplotlib version -============================== +============================ To find out your matplotlib version number, import it and print the ``__version__`` attribute:: @@ -23,7 +23,7 @@ To find out your matplotlib version number, import it and print the .. _locating-matplotlib-install: :file:`matplotlib` install location -==================================== +=================================== You can find what directory matplotlib is installed in by importing it and printing the ``__file__`` attribute:: @@ -35,7 +35,7 @@ and printing the ``__file__`` attribute:: .. _locating-matplotlib-config-dir: :file:`.matplotlib` directory location -======================================== +====================================== Each user has a :file:`.matplotlib/` directory which may contain a :ref:`matplotlibrc ` file and various @@ -63,7 +63,7 @@ environment variable -- see .. _reporting-problems: Report a problem -========================== +================ If you are having a problem with matplotlib, search the mailing lists first: there's a good chance someone else has already run into From cba27cd76e93c1eb3fb077ee7c3efd2dc29dda8e Mon Sep 17 00:00:00 2001 From: cgohlke Date: Tue, 20 Sep 2011 19:26:54 -0700 Subject: [PATCH 155/214] Fix potential issue with np.float16 --- lib/matplotlib/colors.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index bce6a3352d1b..ef93ae8195f9 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -516,7 +516,9 @@ def __call__(self, X, alpha=None, bytes=False): # masked values are substituted below; no need to fill them here if xa.dtype.char in np.typecodes['Float']: - cbook._putmask(xa, xa==1.0, 0.9999999) #Treat 1.0 as slightly less than 1. + # Treat 1.0 as slightly less than 1. + cbook._putmask(xa, xa==1.0, np.nextafter(xa.dtype.type(1), + xa.dtype.type(0))) # The following clip is fast, and prevents possible # conversion of large positive values to negative integers. From 9fe78b6c28405fb44d1864ccf7513d2d12932483 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Wed, 21 Sep 2011 13:06:30 -0500 Subject: [PATCH 156/214] Added mention of the new cubehelix in "what's new" --- doc/users/whats_new.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index e91d675a661b..b2506716e78b 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -189,6 +189,9 @@ Other improvements * Michiel de Hoon has modified the MacOSX backend to make its interactive behavior consistent with the other backends. +* Pim Schellart added a new colormap called "cubehelix". See it and all + other colormaps :ref:`here `. + * Many bug fixes and documentation improvements. .. _whats-new-1-0: From 4772c9d66e6f25b2e2e43632d836875eb6913b5f Mon Sep 17 00:00:00 2001 From: cgohlke Date: Wed, 21 Sep 2011 17:22:09 -0700 Subject: [PATCH 157/214] Add coolwarm color map. Revised patch. Originally submitted by Sameer Grover to matplotlib-devel on 18 Jul 2011. --- lib/matplotlib/_cm.py | 111 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index ceeff9c644bd..d375598c13de 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -1628,6 +1628,115 @@ def gfunc32(x): 'blue': lambda x: 1 - x, } +# This cool to warm color map was generated from Table 2 of +# "Diverging Color Maps for Scientific Visualization (Expanded)" +# by Kenneth Moreland. +_coolwarm_data = { + 'red': [ + (0.0, 0.23137255, 0.23137255), + (0.03125, 0.26666668, 0.26666668), + (0.0625, 0.3019608, 0.3019608), + (0.09375, 0.34117648, 0.34117648), + (0.125, 0.38431373, 0.38431373), + (0.15625, 0.42352942, 0.42352942), + (0.1875, 0.46666667, 0.46666667), + (0.21875, 0.50980395, 0.50980395), + (0.25, 0.5529412, 0.5529412), + (0.28125, 0.59607846, 0.59607846), + (0.3125, 0.63921571, 0.63921571), + (0.34375, 0.68235296, 0.68235296), + (0.375, 0.72156864, 0.72156864), + (0.40625, 0.76078433, 0.76078433), + (0.4375, 0.80000001, 0.80000001), + (0.46875, 0.83529413, 0.83529413), + (0.5, 0.86666667, 0.86666667), + (0.53125, 0.89803922, 0.89803922), + (0.5625, 0.9254902, 0.9254902), + (0.59375, 0.94509804, 0.94509804), + (0.625, 0.96078432, 0.96078432), + (0.65625, 0.96862745, 0.96862745), + (0.6875, 0.96862745, 0.96862745), + (0.71875, 0.96862745, 0.96862745), + (0.75, 0.95686275, 0.95686275), + (0.78125, 0.94509804, 0.94509804), + (0.8125, 0.9254902, 0.9254902), + (0.84375, 0.89803922, 0.89803922), + (0.875, 0.87058824, 0.87058824), + (0.90625, 0.83529413, 0.83529413), + (0.9375, 0.79607844, 0.79607844), + (0.96875, 0.75294119, 0.75294119), + (1.0, 0.70588237, 0.70588237)], + 'green': [ + (0.0, 0.29803923, 0.29803923), + (0.03125, 0.35294119, 0.35294119), + (0.0625, 0.40784314, 0.40784314), + (0.09375, 0.45882353, 0.45882353), + (0.125, 0.50980395, 0.50980395), + (0.15625, 0.55686277, 0.55686277), + (0.1875, 0.60392159, 0.60392159), + (0.21875, 0.64705884, 0.64705884), + (0.25, 0.6901961, 0.6901961), + (0.28125, 0.72549021, 0.72549021), + (0.3125, 0.76078433, 0.76078433), + (0.34375, 0.78823531, 0.78823531), + (0.375, 0.81568629, 0.81568629), + (0.40625, 0.83529413, 0.83529413), + (0.4375, 0.8509804, 0.8509804), + (0.46875, 0.85882354, 0.85882354), + (0.5, 0.86666667, 0.86666667), + (0.53125, 0.84705883, 0.84705883), + (0.5625, 0.82745099, 0.82745099), + (0.59375, 0.80000001, 0.80000001), + (0.625, 0.76862746, 0.76862746), + (0.65625, 0.73333335, 0.73333335), + (0.6875, 0.69411767, 0.69411767), + (0.71875, 0.65098041, 0.65098041), + (0.75, 0.60392159, 0.60392159), + (0.78125, 0.5529412, 0.5529412), + (0.8125, 0.49803922, 0.49803922), + (0.84375, 0.43921569, 0.43921569), + (0.875, 0.3764706, 0.3764706), + (0.90625, 0.3137255, 0.3137255), + (0.9375, 0.24313726, 0.24313726), + (0.96875, 0.15686275, 0.15686275), + (1.0, 0.015686275, 0.015686275)], + 'blue': [ + (0.0, 0.75294119, 0.75294119), + (0.03125, 0.80000001, 0.80000001), + (0.0625, 0.84313726, 0.84313726), + (0.09375, 0.88235295, 0.88235295), + (0.125, 0.91764706, 0.91764706), + (0.15625, 0.94509804, 0.94509804), + (0.1875, 0.96862745, 0.96862745), + (0.21875, 0.98431373, 0.98431373), + (0.25, 0.99607843, 0.99607843), + (0.28125, 1.0, 1.0), + (0.3125, 1.0, 1.0), + (0.34375, 0.99215686, 0.99215686), + (0.375, 0.97647059, 0.97647059), + (0.40625, 0.95686275, 0.95686275), + (0.4375, 0.93333334, 0.93333334), + (0.46875, 0.90196079, 0.90196079), + (0.5, 0.86666667, 0.86666667), + (0.53125, 0.81960785, 0.81960785), + (0.5625, 0.77254903, 0.77254903), + (0.59375, 0.72549021, 0.72549021), + (0.625, 0.67843139, 0.67843139), + (0.65625, 0.627451, 0.627451), + (0.6875, 0.58039218, 0.58039218), + (0.71875, 0.52941179, 0.52941179), + (0.75, 0.48235294, 0.48235294), + (0.78125, 0.43529412, 0.43529412), + (0.8125, 0.3882353, 0.3882353), + (0.84375, 0.34509805, 0.34509805), + (0.875, 0.3019608, 0.3019608), + (0.90625, 0.25882354, 0.25882354), + (0.9375, 0.21960784, 0.21960784), + (0.96875, 0.18431373, 0.18431373), + (1.0, 0.14901961, 0.14901961)] +} + + datad = { 'afmhot': _afmhot_data, 'autumn': _autumn_data, @@ -1700,4 +1809,4 @@ def gfunc32(x): datad['gist_rainbow']=_gist_rainbow_data datad['gist_stern']=_gist_stern_data datad['gist_yarg']=_gist_yarg_data - +datad['coolwarm']=_coolwarm_data From a3ccb0aa359a8896c03ca79d9732b5f8c106c35b Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Thu, 22 Sep 2011 14:31:12 +0900 Subject: [PATCH 158/214] Fix the legend handler for errorbars to work when fmt=None --- lib/matplotlib/legend_handler.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 85790690061b..664a829a103c 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -424,10 +424,6 @@ def create_artists(self, legend, orig_handle, ydata = ((height-ydescent)/2.)*np.ones(xdata.shape, float) legline = Line2D(xdata, ydata) - self.update_prop(legline, plotlines, legend) - legline.set_drawstyle('default') - legline.set_marker('None') - xdata_marker = np.asarray(xdata_marker) ydata_marker = np.asarray(ydata[:len(xdata_marker)]) @@ -437,11 +433,24 @@ def create_artists(self, legend, orig_handle, legline_marker = Line2D(xdata_marker, ydata_marker) - self.update_prop(legline_marker, plotlines, legend) - legline_marker.set_linestyle('None') - if legend.markerscale !=1: - newsz = legline_marker.get_markersize()*legend.markerscale - legline_marker.set_markersize(newsz) + + # when plotlines are None (only errorbars are drawn), we just + # make legline invisible. + if plotlines is None: + legline.set_visible(False) + legline_marker.set_visible(False) + else: + self.update_prop(legline, plotlines, legend) + + legline.set_drawstyle('default') + legline.set_marker('None') + + self.update_prop(legline_marker, plotlines, legend) + legline_marker.set_linestyle('None') + + if legend.markerscale !=1: + newsz = legline_marker.get_markersize()*legend.markerscale + legline_marker.set_markersize(newsz) handle_barlinecols = [] From 3a68d1adacace0b69b082a0c3c2ca74d2793665b Mon Sep 17 00:00:00 2001 From: Ben Root Date: Thu, 22 Sep 2011 15:28:41 -0500 Subject: [PATCH 159/214] Added a Lorenz Attractor example for mplot3d. Why? Because butterflies are awesome! --- examples/mplot3d/lorenz_attractor.py | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 examples/mplot3d/lorenz_attractor.py diff --git a/examples/mplot3d/lorenz_attractor.py b/examples/mplot3d/lorenz_attractor.py new file mode 100644 index 000000000000..635605c9c1e2 --- /dev/null +++ b/examples/mplot3d/lorenz_attractor.py @@ -0,0 +1,49 @@ +# Plot of the Lorenz Attractor based on Edward Lorenz's 1963 "Deterministic +# Nonperiodic Flow" publication. +# http://journals.ametsoc.org/doi/abs/10.1175/1520-0469%281963%29020%3C0130%3ADNF%3E2.0.CO%3B2 +# +# Note: Because this is a simple non-linear ODE, it would be more easily +# done using SciPy's ode solver, but this approach depends only +# upon NumPy. + +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D + + +def lorenz(x, y, z, s=10, r=28, b=2.667) : + x_dot = s*(y - x) + y_dot = r*x - y - x*z + z_dot = x*y - b*z + return x_dot, y_dot, z_dot + + +dt = 0.01 +stepCnt = 10000 + +# Need one more for the initial values +xs = np.empty((stepCnt + 1,)) +ys = np.empty((stepCnt + 1,)) +zs = np.empty((stepCnt + 1,)) + +# Setting initial values +xs[0], ys[0], zs[0] = (0., 1., 1.05) + +# Stepping through "time". +for i in xrange(stepCnt) : + # Derivatives of the X, Y, Z state + x_dot, y_dot, z_dot = lorenz(xs[i], ys[i], zs[i]) + xs[i + 1] = xs[i] + (x_dot * dt) + ys[i + 1] = ys[i] + (y_dot * dt) + zs[i + 1] = zs[i] + (z_dot * dt) + +fig = plt.figure() +ax = fig.gca(projection='3d') + +ax.plot(xs, ys, zs) +ax.set_xlabel("X Axis") +ax.set_ylabel("Y Axis") +ax.set_zlabel("Z Axis") + +plt.show() + From f16efdf0147c6c947a0fb651e25bde38c375a55c Mon Sep 17 00:00:00 2001 From: cgohlke Date: Thu, 22 Sep 2011 22:09:28 -0700 Subject: [PATCH 160/214] Revised coolwarm color map with data from CoolWarmFloat33.csv --- lib/matplotlib/_cm.py | 206 +++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index d375598c13de..fc92aef278f9 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -1628,113 +1628,113 @@ def gfunc32(x): 'blue': lambda x: 1 - x, } -# This cool to warm color map was generated from Table 2 of -# "Diverging Color Maps for Scientific Visualization (Expanded)" -# by Kenneth Moreland. +# This bipolar color map was generated from CoolWarmFloat33.csv of +# "Diverging Color Maps for Scientific Visualization" by Kenneth Moreland. +# _coolwarm_data = { 'red': [ - (0.0, 0.23137255, 0.23137255), - (0.03125, 0.26666668, 0.26666668), - (0.0625, 0.3019608, 0.3019608), - (0.09375, 0.34117648, 0.34117648), - (0.125, 0.38431373, 0.38431373), - (0.15625, 0.42352942, 0.42352942), - (0.1875, 0.46666667, 0.46666667), - (0.21875, 0.50980395, 0.50980395), - (0.25, 0.5529412, 0.5529412), - (0.28125, 0.59607846, 0.59607846), - (0.3125, 0.63921571, 0.63921571), - (0.34375, 0.68235296, 0.68235296), - (0.375, 0.72156864, 0.72156864), - (0.40625, 0.76078433, 0.76078433), - (0.4375, 0.80000001, 0.80000001), - (0.46875, 0.83529413, 0.83529413), - (0.5, 0.86666667, 0.86666667), - (0.53125, 0.89803922, 0.89803922), - (0.5625, 0.9254902, 0.9254902), - (0.59375, 0.94509804, 0.94509804), - (0.625, 0.96078432, 0.96078432), - (0.65625, 0.96862745, 0.96862745), - (0.6875, 0.96862745, 0.96862745), - (0.71875, 0.96862745, 0.96862745), - (0.75, 0.95686275, 0.95686275), - (0.78125, 0.94509804, 0.94509804), - (0.8125, 0.9254902, 0.9254902), - (0.84375, 0.89803922, 0.89803922), - (0.875, 0.87058824, 0.87058824), - (0.90625, 0.83529413, 0.83529413), - (0.9375, 0.79607844, 0.79607844), - (0.96875, 0.75294119, 0.75294119), - (1.0, 0.70588237, 0.70588237)], + (0.0, 0.2298057, 0.2298057), + (0.03125, 0.26623388, 0.26623388), + (0.0625, 0.30386891, 0.30386891), + (0.09375, 0.342804478, 0.342804478), + (0.125, 0.38301334, 0.38301334), + (0.15625, 0.424369608, 0.424369608), + (0.1875, 0.46666708, 0.46666708), + (0.21875, 0.509635204, 0.509635204), + (0.25, 0.552953156, 0.552953156), + (0.28125, 0.596262162, 0.596262162), + (0.3125, 0.639176211, 0.639176211), + (0.34375, 0.681291281, 0.681291281), + (0.375, 0.722193294, 0.722193294), + (0.40625, 0.761464949, 0.761464949), + (0.4375, 0.798691636, 0.798691636), + (0.46875, 0.833466556, 0.833466556), + (0.5, 0.865395197, 0.865395197), + (0.53125, 0.897787179, 0.897787179), + (0.5625, 0.924127593, 0.924127593), + (0.59375, 0.944468518, 0.944468518), + (0.625, 0.958852946, 0.958852946), + (0.65625, 0.96732803, 0.96732803), + (0.6875, 0.969954137, 0.969954137), + (0.71875, 0.966811177, 0.966811177), + (0.75, 0.958003065, 0.958003065), + (0.78125, 0.943660866, 0.943660866), + (0.8125, 0.923944917, 0.923944917), + (0.84375, 0.89904617, 0.89904617), + (0.875, 0.869186849, 0.869186849), + (0.90625, 0.834620542, 0.834620542), + (0.9375, 0.795631745, 0.795631745), + (0.96875, 0.752534934, 0.752534934), + (1.0, 0.705673158, 0.705673158)], 'green': [ - (0.0, 0.29803923, 0.29803923), - (0.03125, 0.35294119, 0.35294119), - (0.0625, 0.40784314, 0.40784314), - (0.09375, 0.45882353, 0.45882353), - (0.125, 0.50980395, 0.50980395), - (0.15625, 0.55686277, 0.55686277), - (0.1875, 0.60392159, 0.60392159), - (0.21875, 0.64705884, 0.64705884), - (0.25, 0.6901961, 0.6901961), - (0.28125, 0.72549021, 0.72549021), - (0.3125, 0.76078433, 0.76078433), - (0.34375, 0.78823531, 0.78823531), - (0.375, 0.81568629, 0.81568629), - (0.40625, 0.83529413, 0.83529413), - (0.4375, 0.8509804, 0.8509804), - (0.46875, 0.85882354, 0.85882354), - (0.5, 0.86666667, 0.86666667), - (0.53125, 0.84705883, 0.84705883), - (0.5625, 0.82745099, 0.82745099), - (0.59375, 0.80000001, 0.80000001), - (0.625, 0.76862746, 0.76862746), - (0.65625, 0.73333335, 0.73333335), - (0.6875, 0.69411767, 0.69411767), - (0.71875, 0.65098041, 0.65098041), - (0.75, 0.60392159, 0.60392159), - (0.78125, 0.5529412, 0.5529412), - (0.8125, 0.49803922, 0.49803922), - (0.84375, 0.43921569, 0.43921569), - (0.875, 0.3764706, 0.3764706), - (0.90625, 0.3137255, 0.3137255), - (0.9375, 0.24313726, 0.24313726), - (0.96875, 0.15686275, 0.15686275), - (1.0, 0.015686275, 0.015686275)], + (0.0, 0.298717966, 0.298717966), + (0.03125, 0.353094838, 0.353094838), + (0.0625, 0.406535296, 0.406535296), + (0.09375, 0.458757618, 0.458757618), + (0.125, 0.50941904, 0.50941904), + (0.15625, 0.558148092, 0.558148092), + (0.1875, 0.604562568, 0.604562568), + (0.21875, 0.648280772, 0.648280772), + (0.25, 0.688929332, 0.688929332), + (0.28125, 0.726149107, 0.726149107), + (0.3125, 0.759599947, 0.759599947), + (0.34375, 0.788964712, 0.788964712), + (0.375, 0.813952739, 0.813952739), + (0.40625, 0.834302879, 0.834302879), + (0.4375, 0.849786142, 0.849786142), + (0.46875, 0.860207984, 0.860207984), + (0.5, 0.86541021, 0.86541021), + (0.53125, 0.848937047, 0.848937047), + (0.5625, 0.827384882, 0.827384882), + (0.59375, 0.800927443, 0.800927443), + (0.625, 0.769767752, 0.769767752), + (0.65625, 0.734132809, 0.734132809), + (0.6875, 0.694266682, 0.694266682), + (0.71875, 0.650421156, 0.650421156), + (0.75, 0.602842431, 0.602842431), + (0.78125, 0.551750968, 0.551750968), + (0.8125, 0.49730856, 0.49730856), + (0.84375, 0.439559467, 0.439559467), + (0.875, 0.378313092, 0.378313092), + (0.90625, 0.312874446, 0.312874446), + (0.9375, 0.24128379, 0.24128379), + (0.96875, 0.157246067, 0.157246067), + (1.0, 0.01555616, 0.01555616)], 'blue': [ - (0.0, 0.75294119, 0.75294119), - (0.03125, 0.80000001, 0.80000001), - (0.0625, 0.84313726, 0.84313726), - (0.09375, 0.88235295, 0.88235295), - (0.125, 0.91764706, 0.91764706), - (0.15625, 0.94509804, 0.94509804), - (0.1875, 0.96862745, 0.96862745), - (0.21875, 0.98431373, 0.98431373), - (0.25, 0.99607843, 0.99607843), - (0.28125, 1.0, 1.0), - (0.3125, 1.0, 1.0), - (0.34375, 0.99215686, 0.99215686), - (0.375, 0.97647059, 0.97647059), - (0.40625, 0.95686275, 0.95686275), - (0.4375, 0.93333334, 0.93333334), - (0.46875, 0.90196079, 0.90196079), - (0.5, 0.86666667, 0.86666667), - (0.53125, 0.81960785, 0.81960785), - (0.5625, 0.77254903, 0.77254903), - (0.59375, 0.72549021, 0.72549021), - (0.625, 0.67843139, 0.67843139), - (0.65625, 0.627451, 0.627451), - (0.6875, 0.58039218, 0.58039218), - (0.71875, 0.52941179, 0.52941179), - (0.75, 0.48235294, 0.48235294), - (0.78125, 0.43529412, 0.43529412), - (0.8125, 0.3882353, 0.3882353), - (0.84375, 0.34509805, 0.34509805), - (0.875, 0.3019608, 0.3019608), - (0.90625, 0.25882354, 0.25882354), - (0.9375, 0.21960784, 0.21960784), - (0.96875, 0.18431373, 0.18431373), - (1.0, 0.14901961, 0.14901961)] -} + (0.0, 0.753683153, 0.753683153), + (0.03125, 0.801466763, 0.801466763), + (0.0625, 0.84495867, 0.84495867), + (0.09375, 0.883725899, 0.883725899), + (0.125, 0.917387822, 0.917387822), + (0.15625, 0.945619588, 0.945619588), + (0.1875, 0.968154911, 0.968154911), + (0.21875, 0.98478814, 0.98478814), + (0.25, 0.995375608, 0.995375608), + (0.28125, 0.999836203, 0.999836203), + (0.3125, 0.998151185, 0.998151185), + (0.34375, 0.990363227, 0.990363227), + (0.375, 0.976574709, 0.976574709), + (0.40625, 0.956945269, 0.956945269), + (0.4375, 0.931688648, 0.931688648), + (0.46875, 0.901068838, 0.901068838), + (0.5, 0.865395561, 0.865395561), + (0.53125, 0.820880546, 0.820880546), + (0.5625, 0.774508472, 0.774508472), + (0.59375, 0.726736146, 0.726736146), + (0.625, 0.678007945, 0.678007945), + (0.65625, 0.628751763, 0.628751763), + (0.6875, 0.579375448, 0.579375448), + (0.71875, 0.530263762, 0.530263762), + (0.75, 0.481775914, 0.481775914), + (0.78125, 0.434243684, 0.434243684), + (0.8125, 0.387970225, 0.387970225), + (0.84375, 0.343229596, 0.343229596), + (0.875, 0.300267182, 0.300267182), + (0.90625, 0.259301199, 0.259301199), + (0.9375, 0.220525627, 0.220525627), + (0.96875, 0.184115123, 0.184115123), + (1.0, 0.150232812, 0.150232812)] + } datad = { From 10ea86ca57497cdb6a5a50f70bcbbdebeefb27c0 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 23 Sep 2011 11:28:38 -0400 Subject: [PATCH 161/214] Don't call asarray on returning the arrays from the symlog transforms. --- lib/matplotlib/scale.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 5194503f5558..870a3cfb5854 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -328,11 +328,9 @@ def transform(self, a): masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) log = sign * self.linthresh * (1 + ma.log(np.abs(masked) / self.linthresh)) if masked.mask.any(): - return np.asarray(ma.where(masked.mask, - a, - log)) + return ma.where(masked.mask, a, log) else: - return np.asarray(log) + return log def inverted(self): return SymmetricalLogScale.InvertedSymmetricalLogTransform(self.base, self.linthresh) @@ -355,11 +353,9 @@ def transform(self, a): masked = ma.masked_inside(a, -self.linthresh, self.linthresh, copy=False) exp = sign * self.linthresh * ma.exp(sign * masked / self.linthresh - 1) if masked.mask.any(): - return np.asarray(ma.where(masked.mask, - a, - exp)) + return ma.where(masked.mask, a, exp) else: - return np.asarray(exp) + return exp def __init__(self, axis, **kwargs): """ From c4a0e797236e8b72ca5f0ae346a30e0f1855919c Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 11:59:28 -0500 Subject: [PATCH 162/214] Added comment about the recently added coolwarm colormap. --- doc/users/whats_new.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index b2506716e78b..deea56843eb3 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -189,7 +189,8 @@ Other improvements * Michiel de Hoon has modified the MacOSX backend to make its interactive behavior consistent with the other backends. -* Pim Schellart added a new colormap called "cubehelix". See it and all +* Pim Schellart added a new colormap called "cubehelix". + Sameer Grover also added a colormap called "coolwarm". See it and all other colormaps :ref:`here `. * Many bug fixes and documentation improvements. From da02c1c15ac9bf87b7904d5456c493500ec5cf09 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 16:17:22 -0500 Subject: [PATCH 163/214] Some more doc cleanup... Still need to figure out users/installing.rst --- doc/faq/installing_faq.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst index 26d843a8fd98..25f0fb833d8a 100644 --- a/doc/faq/installing_faq.rst +++ b/doc/faq/installing_faq.rst @@ -135,13 +135,19 @@ and build and install as usual with:: build dependencies, which will make building from source easier. -If you want to be able to follow the development branch as it changes just replace -the last step with (make sure you have **setuptools** installed):: +If you want to be able to follow the development branch as it changes +just replace the last step with (make sure you have **setuptools** +installed):: > python setupegg.py develop -This creates links in the right places and installs the command line script to the appropriate places. -Then, if you want to update your **matplotlib** at any time, just do:: +This creates links in the right places and installs the command +line script to the appropriate places. + +.. note:: + Mac OSX users please see the :ref:`build_osx` guide. + +Then, if you want to update your matplotlib at any time, just do:: > git pull From 604d0c4211f514096635af969a4d034ab0891818 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 17:55:01 -0500 Subject: [PATCH 164/214] Remove erroneous entry in .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 43c7c5ef6bda..2072e27a74f7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,5 +45,4 @@ lib/matplotlib/mpl-data/matplotlibrc ################################# doc/examples doc/_templates/gallery.html -doc/users/installing.rst doc/_static/matplotlibrc From 74b580ff2f52232749f75907e82f3315db8859a8 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 18:09:02 -0500 Subject: [PATCH 165/214] Style clean-up of doc/users/installing.rst --- doc/users/installing.rst | 253 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 doc/users/installing.rst diff --git a/doc/users/installing.rst b/doc/users/installing.rst new file mode 100644 index 000000000000..4ef56d2af9b7 --- /dev/null +++ b/doc/users/installing.rst @@ -0,0 +1,253 @@ +********** +Installing +********** + +There are lots of different ways to install matplotlib, and the best +way depends on what operating system you are using, what you already +have installed, and how you want to use it. To avoid wading through +all the details (and potential complications) on this page, the +easiest thing for you to do is use one of the pre-packaged python +distributions that already provide matplotlib built-in. The Enthought +Python Distribution `(EPD) +`_ for Windows, OS X or +Redhat is an excellent choice that "just works" out of the box. +Another excellent alternative for Windows users is `Python (x, y) +`_ which tends to be updated a +bit more frequently. Both of these packages include matplotlib and +pylab, and *lots* of other useful tools. matplotlib is also packaged +for almost every major Linux distribution. So if you are on Linux, +your package manager will probably provide matplotlib prebuilt. + + +Manually installing pre-built packages +====================================== + +General instructions +-------------------- + +For some people, the prepackaged pythons discussed above are not an +option. That's OK, it's usually pretty easy to get a custom install +working. You will first need to find out if you have python installed +on your machine, and if not, install it. The official python builds +are available for download `here `_, +but OS X users please read :ref:`which-python-for-osx`. + +Once you have python up and running, you will need to install `numpy +`_. +numpy provides high-performance array data structures and mathematical +functions, and is a requirement for matplotlib. You can test your +progress:: + + >>> import numpy + >>> print numpy.__version__ + +matplotlib requires numpy version 1.1 or later. Although it is not a +requirement to use matplotlib, we strongly encourage you to install +`ipython `_, which is an interactive +shell for python that is matplotlib-aware. + +Next, we need to get matplotlib installed. We provide prebuilt +binaries for OS X and Windows on the matplotlib `download +`_ page. Click on +the latest release of the "matplotlib" package, choose your python +version (e.g., 2.5, 2.6 or 2.7) and your platform (macosx or win32). +If you have any problems, please check the :ref:`installing-faq`, +search using Google, and/or post a question to the `mailing list +`_. + +If you are on Debian/Ubuntu Linux, it suffices to do:: + + > sudo apt-get install python-matplotlib + +Instructions for installing our OSX binaries are found in the FAQ +:ref:`install_osx_binaries`. + + +Once you have ipython, numpy and matplotlib installed, you can use +ipython's "pylab" mode to have a MATLAB-like environment that automatically +handles most of the configuration details for you, so you can get up +and running quickly:: + + johnh@flag:~> ipython -pylab + Python 2.4.5 (#4, Apr 12 2008, 09:09:16) + IPython 0.9.0 -- An enhanced Interactive Python. + + Welcome to pylab, a matplotlib-based Python environment. + For more information, type 'help(pylab)'. + + In [1]: x = randn(10000) + + In [2]: hist(x, 100) + +Note that when testing matplotlib installations from the interactive +python console, there are some issues relating to user interface +toolkits and interactive settings that are discussed in +:ref:`mpl-shell`. + +Installing on Windows +--------------------- + +If you don't already have python installed, you may want to consider +using the Enthought edition of python, which has scipy, numpy, and +wxpython, plus many other useful packages, preinstalled - `Enthought +Python `_. With the Enthought +edition of python + matplotlib installer, the following backends +should work out of the box: agg, wx, wxagg, tkagg, ps, pdf and svg. + +For standard python installations, you will also need to install numpy +in addition to the matplotlib installer. On some systems you will +also need to download msvcp71.dll library, which you can download from +http://www.dll-files.com/dllindex/dll-files.shtml?msvcp71 or other +sites. You will need to unzip the archive and drag the dll into +:file:`c:\windows\system32`. + +All of the GUI backends run on Windows, but TkAgg is probably the +best for interactive use from the standard python shell or ipython. +The Windows installer (:file:`*.exe`) on the download page contains all the +code you need to get up and running. However, there are many +examples that are not included in the Windows installer. If you +want to try the many demos that come in the matplotlib source +distribution, download the zip file and look in the :file:`examples` +subdirectory. + +.. _install_from_source: + +Installing from source +====================== + +If you are interested in contributing to matplotlib +development, running the latest source code, or just like to +build everything yourself, it is not difficult to build matplotlib +from source. Grab the latest *tar.gz* release file from `sourceforge +`_, or if +you want to develop matplotlib or just need the latest bugfixed +version, grab the latest git version :ref:`install-from-git`. + +Once you have satisfied the requirements detailed below (mainly +python, numpy, libpng and freetype), you can build matplotlib:: + + cd matplotlib + python setup.py build + python setup.py install + +We provide a `setup.cfg +`_ +file that goes with :file:`setup.py` which you can use to customize +the build process. For example, which default backend to use, whether +some of the optional libraries that matplotlib ships with are +installed, and so on. This file will be particularly useful to those +packaging matplotlib. + +If you have installed prerequisites to nonstandard places and need to +inform matplotlib where they are, edit ``setupext.py`` and add the base +dirs to the ``basedir`` dictionary entry for your ``sys.platform``. +e.g., if the header to some required library is in +``/some/path/include/someheader.h``, put ``/some/path`` in the +``basedir`` list for your platform. + +.. _install_requirements: + +Build requirements +================== + +These are external packages which you will need to install before +installing matplotlib. Windows users only need the first two (python +and numpy) since the others are built into the matplotlib Windows +installers available for download at the sourceforge site. If you are +building on OSX, see :ref:`build_osx`. If you are installing +dependencies with a package manager on Linux, you may need to install the +development packages (look for a "-dev" postfix) in addition to the +libraries themselves. + +.. note:: + + If you are on debian/ubuntu, you can get all the dependencies + required to build matplotlib with:: + + sudo apt-get build-dep python-matplotlib + + If you are on Fedora/RedHat, you can get all the dependencies + required to build matplotlib by first installing ``yum-builddep`` + and then running:: + + su -c "yum-builddep python-matplotlib" + + This does not build matplotlib, but it does get the install the + build dependencies, which will make building from source easier. + +:term:`python` 2.4 (or later but not python3) + matplotlib requires python 2.4 or later (`download `__) + +:term:`numpy` 1.1 (or later) + array support for python (`download + `__) + +libpng 1.2 (or later) + library for loading and saving :term:`PNG` files (`download + `__). libpng requires + zlib. If you are a Windows user, you can ignore this because we + build support into the matplotlib single-click installer + +:term:`freetype` 1.4 (or later) + library for reading true type font files. If you are a windows + user, you can ignore this since we build support into the + matplotlib single click installer. + +**Optional** + +These are optional packages which you may want to install to use +matplotlib with a user interface toolkit. See +:ref:`what-is-a-backend` for more details on the optional matplotlib +backends and the capabilities they provide. + +:term:`tk` 8.3 or later + The TCL/Tk widgets library used by the TkAgg backend + +:term:`pyqt` 3.1 or later + The Qt3 widgets library python wrappers for the QtAgg backend + +:term:`pyqt` 4.0 or later + The Qt4 widgets library python wrappers for the Qt4Agg backend + +:term:`pygtk` 2.4 or later + The python wrappers for the GTK widgets library for use with the + GTK or GTKAgg backend + +:term:`wxpython` 2.8 or later + The python wrappers for the wx widgets library for use with the + WX or WXAgg backend + +:term:`pyfltk` 1.0 or later + The python wrappers of the FLTK widgets library for use with FLTKAgg + +**Required libraries that ship with matplotlib** + +:term:`agg` 2.4 + The antigrain C++ rendering engine. matplotlib links against the + agg template source statically, so it will not affect anything on + your system outside of matplotlib. + +:term:`pytz` 2007g or later + timezone handling for python datetime objects. By default, + matplotlib will install pytz if it isn't already installed on your + system. To override the default, use :file:`setup.cfg` to force or + prevent installation of pytz. + +:term:`dateutil` 1.1 or later + provides extensions to python datetime handling. By default, matplotlib + will install dateutil if it isn't already installed on your + system. To override the default, use :file:`setup.cfg` to force + or prevent installation of dateutil. + +.. _build_osx: + +Building on OSX +=============== + +The build situation on OSX is complicated by the various places one +can get the libpng and freetype requirements (darwinports, fink, +/usr/X11R6) and the different architectures (e.g., x86, ppc, universal) and +the different OSX version (e.g., 10.4 and 10.5). We recommend that you build +the way we do for the OSX release: get the source from the tarball or the +git repository and follow the instruction in :file:`README.osx`. + From d7dd6d5351ef11642697fabd773ca7b52ca492bb Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 19:43:13 -0500 Subject: [PATCH 166/214] Revert "Style clean-up of doc/users/installing.rst" This reverts commit 74b580ff2f52232749f75907e82f3315db8859a8. --- doc/users/installing.rst | 253 --------------------------------------- 1 file changed, 253 deletions(-) delete mode 100644 doc/users/installing.rst diff --git a/doc/users/installing.rst b/doc/users/installing.rst deleted file mode 100644 index 4ef56d2af9b7..000000000000 --- a/doc/users/installing.rst +++ /dev/null @@ -1,253 +0,0 @@ -********** -Installing -********** - -There are lots of different ways to install matplotlib, and the best -way depends on what operating system you are using, what you already -have installed, and how you want to use it. To avoid wading through -all the details (and potential complications) on this page, the -easiest thing for you to do is use one of the pre-packaged python -distributions that already provide matplotlib built-in. The Enthought -Python Distribution `(EPD) -`_ for Windows, OS X or -Redhat is an excellent choice that "just works" out of the box. -Another excellent alternative for Windows users is `Python (x, y) -`_ which tends to be updated a -bit more frequently. Both of these packages include matplotlib and -pylab, and *lots* of other useful tools. matplotlib is also packaged -for almost every major Linux distribution. So if you are on Linux, -your package manager will probably provide matplotlib prebuilt. - - -Manually installing pre-built packages -====================================== - -General instructions --------------------- - -For some people, the prepackaged pythons discussed above are not an -option. That's OK, it's usually pretty easy to get a custom install -working. You will first need to find out if you have python installed -on your machine, and if not, install it. The official python builds -are available for download `here `_, -but OS X users please read :ref:`which-python-for-osx`. - -Once you have python up and running, you will need to install `numpy -`_. -numpy provides high-performance array data structures and mathematical -functions, and is a requirement for matplotlib. You can test your -progress:: - - >>> import numpy - >>> print numpy.__version__ - -matplotlib requires numpy version 1.1 or later. Although it is not a -requirement to use matplotlib, we strongly encourage you to install -`ipython `_, which is an interactive -shell for python that is matplotlib-aware. - -Next, we need to get matplotlib installed. We provide prebuilt -binaries for OS X and Windows on the matplotlib `download -`_ page. Click on -the latest release of the "matplotlib" package, choose your python -version (e.g., 2.5, 2.6 or 2.7) and your platform (macosx or win32). -If you have any problems, please check the :ref:`installing-faq`, -search using Google, and/or post a question to the `mailing list -`_. - -If you are on Debian/Ubuntu Linux, it suffices to do:: - - > sudo apt-get install python-matplotlib - -Instructions for installing our OSX binaries are found in the FAQ -:ref:`install_osx_binaries`. - - -Once you have ipython, numpy and matplotlib installed, you can use -ipython's "pylab" mode to have a MATLAB-like environment that automatically -handles most of the configuration details for you, so you can get up -and running quickly:: - - johnh@flag:~> ipython -pylab - Python 2.4.5 (#4, Apr 12 2008, 09:09:16) - IPython 0.9.0 -- An enhanced Interactive Python. - - Welcome to pylab, a matplotlib-based Python environment. - For more information, type 'help(pylab)'. - - In [1]: x = randn(10000) - - In [2]: hist(x, 100) - -Note that when testing matplotlib installations from the interactive -python console, there are some issues relating to user interface -toolkits and interactive settings that are discussed in -:ref:`mpl-shell`. - -Installing on Windows ---------------------- - -If you don't already have python installed, you may want to consider -using the Enthought edition of python, which has scipy, numpy, and -wxpython, plus many other useful packages, preinstalled - `Enthought -Python `_. With the Enthought -edition of python + matplotlib installer, the following backends -should work out of the box: agg, wx, wxagg, tkagg, ps, pdf and svg. - -For standard python installations, you will also need to install numpy -in addition to the matplotlib installer. On some systems you will -also need to download msvcp71.dll library, which you can download from -http://www.dll-files.com/dllindex/dll-files.shtml?msvcp71 or other -sites. You will need to unzip the archive and drag the dll into -:file:`c:\windows\system32`. - -All of the GUI backends run on Windows, but TkAgg is probably the -best for interactive use from the standard python shell or ipython. -The Windows installer (:file:`*.exe`) on the download page contains all the -code you need to get up and running. However, there are many -examples that are not included in the Windows installer. If you -want to try the many demos that come in the matplotlib source -distribution, download the zip file and look in the :file:`examples` -subdirectory. - -.. _install_from_source: - -Installing from source -====================== - -If you are interested in contributing to matplotlib -development, running the latest source code, or just like to -build everything yourself, it is not difficult to build matplotlib -from source. Grab the latest *tar.gz* release file from `sourceforge -`_, or if -you want to develop matplotlib or just need the latest bugfixed -version, grab the latest git version :ref:`install-from-git`. - -Once you have satisfied the requirements detailed below (mainly -python, numpy, libpng and freetype), you can build matplotlib:: - - cd matplotlib - python setup.py build - python setup.py install - -We provide a `setup.cfg -`_ -file that goes with :file:`setup.py` which you can use to customize -the build process. For example, which default backend to use, whether -some of the optional libraries that matplotlib ships with are -installed, and so on. This file will be particularly useful to those -packaging matplotlib. - -If you have installed prerequisites to nonstandard places and need to -inform matplotlib where they are, edit ``setupext.py`` and add the base -dirs to the ``basedir`` dictionary entry for your ``sys.platform``. -e.g., if the header to some required library is in -``/some/path/include/someheader.h``, put ``/some/path`` in the -``basedir`` list for your platform. - -.. _install_requirements: - -Build requirements -================== - -These are external packages which you will need to install before -installing matplotlib. Windows users only need the first two (python -and numpy) since the others are built into the matplotlib Windows -installers available for download at the sourceforge site. If you are -building on OSX, see :ref:`build_osx`. If you are installing -dependencies with a package manager on Linux, you may need to install the -development packages (look for a "-dev" postfix) in addition to the -libraries themselves. - -.. note:: - - If you are on debian/ubuntu, you can get all the dependencies - required to build matplotlib with:: - - sudo apt-get build-dep python-matplotlib - - If you are on Fedora/RedHat, you can get all the dependencies - required to build matplotlib by first installing ``yum-builddep`` - and then running:: - - su -c "yum-builddep python-matplotlib" - - This does not build matplotlib, but it does get the install the - build dependencies, which will make building from source easier. - -:term:`python` 2.4 (or later but not python3) - matplotlib requires python 2.4 or later (`download `__) - -:term:`numpy` 1.1 (or later) - array support for python (`download - `__) - -libpng 1.2 (or later) - library for loading and saving :term:`PNG` files (`download - `__). libpng requires - zlib. If you are a Windows user, you can ignore this because we - build support into the matplotlib single-click installer - -:term:`freetype` 1.4 (or later) - library for reading true type font files. If you are a windows - user, you can ignore this since we build support into the - matplotlib single click installer. - -**Optional** - -These are optional packages which you may want to install to use -matplotlib with a user interface toolkit. See -:ref:`what-is-a-backend` for more details on the optional matplotlib -backends and the capabilities they provide. - -:term:`tk` 8.3 or later - The TCL/Tk widgets library used by the TkAgg backend - -:term:`pyqt` 3.1 or later - The Qt3 widgets library python wrappers for the QtAgg backend - -:term:`pyqt` 4.0 or later - The Qt4 widgets library python wrappers for the Qt4Agg backend - -:term:`pygtk` 2.4 or later - The python wrappers for the GTK widgets library for use with the - GTK or GTKAgg backend - -:term:`wxpython` 2.8 or later - The python wrappers for the wx widgets library for use with the - WX or WXAgg backend - -:term:`pyfltk` 1.0 or later - The python wrappers of the FLTK widgets library for use with FLTKAgg - -**Required libraries that ship with matplotlib** - -:term:`agg` 2.4 - The antigrain C++ rendering engine. matplotlib links against the - agg template source statically, so it will not affect anything on - your system outside of matplotlib. - -:term:`pytz` 2007g or later - timezone handling for python datetime objects. By default, - matplotlib will install pytz if it isn't already installed on your - system. To override the default, use :file:`setup.cfg` to force or - prevent installation of pytz. - -:term:`dateutil` 1.1 or later - provides extensions to python datetime handling. By default, matplotlib - will install dateutil if it isn't already installed on your - system. To override the default, use :file:`setup.cfg` to force - or prevent installation of dateutil. - -.. _build_osx: - -Building on OSX -=============== - -The build situation on OSX is complicated by the various places one -can get the libpng and freetype requirements (darwinports, fink, -/usr/X11R6) and the different architectures (e.g., x86, ppc, universal) and -the different OSX version (e.g., 10.4 and 10.5). We recommend that you build -the way we do for the OSX release: get the source from the tarball or the -git repository and follow the instruction in :file:`README.osx`. - From 43ee8cbbc17a3570d9b0add799e09d6979c5e01f Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 19:43:40 -0500 Subject: [PATCH 167/214] Revert "Remove erroneous entry in .gitignore" This reverts commit 604d0c4211f514096635af969a4d034ab0891818. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2072e27a74f7..43c7c5ef6bda 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ lib/matplotlib/mpl-data/matplotlibrc ################################# doc/examples doc/_templates/gallery.html +doc/users/installing.rst doc/_static/matplotlibrc From a07e2f791bb9dba27ec40f7f70fde044fd866cef Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 20:28:17 -0500 Subject: [PATCH 168/214] Style cleanup of INSTALL contents. Also added note to INSTALL that its contents gets copied during the doc-build process. Also added that copied file to the "clean" target of the docs' make.py. --- INSTALL | 76 +++++++++++++++++++++++++++-------------------------- doc/make.py | 3 ++- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/INSTALL b/INSTALL index e720a3d5e01b..08fc3ab05629 100644 --- a/INSTALL +++ b/INSTALL @@ -1,8 +1,12 @@ +.. The source of this document is INSTALL. During the doc build process, +.. this file is copied over to doc/users/installing.rst. +.. Therefore, you must edit INSTALL, *not* doc/users/installing.rst! + ********** Installing ********** -There are lots of different ways to install matplotlib, and the best +There are many different ways to install matplotlib, and the best way depends on what operating system you are using, what you already have installed, and how you want to use it. To avoid wading through all the details (and potential complications) on this page, the @@ -15,14 +19,16 @@ Another excellent alternative for Windows users is `Python (x, y) `_ which tends to be updated a bit more frequently. Both of these packages include matplotlib and pylab, and *lots* of other useful tools. matplotlib is also packaged -for almost every major linux distribution. So if you are on linux, +for almost every major Linux distribution. So if you are on Linux, your package manager will probably provide matplotlib prebuilt. -One single click installer and you are done. Manually installing pre-built packages ====================================== +General instructions +-------------------- + For some people, the prepackaged pythons discussed above are not an option. That's OK, it's usually pretty easy to get a custom install working. You will first need to find out if you have python installed @@ -48,12 +54,12 @@ Next, we need to get matplotlib installed. We provide prebuilt binaries for OS X and Windows on the matplotlib `download `_ page. Click on the latest release of the "matplotlib" package, choose your python -version (2.5, 2.6 or 2.7) and your platform (macosx or win32) and you -should be good to go. If you have any problems, please check the -:ref:`installing-faq`, google around a little bit, and post a question -the `mailing list -`_. If -you are on debian/ubuntu linux, it suffices to do:: +version (e.g., 2.5, 2.6 or 2.7) and your platform (macosx or win32). +If you have any problems, please check the :ref:`installing-faq`, +search using Google, and/or post a question to the `mailing list +`_. + +If you are on Debian/Ubuntu Linux, it suffices to do:: > sudo apt-get install python-matplotlib @@ -61,8 +67,8 @@ Instructions for installing our OSX binaries are found in the FAQ :ref:`install_osx_binaries`. -Once you have ipython, numpy and matplotlib installed, in ipython's -"pylab" mode you have a MATLAB-like environment that automatically +Once you have ipython, numpy and matplotlib installed, you can use +ipython's "pylab" mode to have a MATLAB-like environment that automatically handles most of the configuration details for you, so you can get up and running quickly:: @@ -86,9 +92,9 @@ Installing on Windows --------------------- If you don't already have python installed, you may want to consider -using the enthought edition of python, which has scipy, numpy, and -wxpython, plus a lot of other goodies, preinstalled - `Enthought -Python `_. With the enthought +using the Enthought edition of python, which has scipy, numpy, and +wxpython, plus many other useful packages, preinstalled - `Enthought +Python `_. With the Enthought edition of python + matplotlib installer, the following backends should work out of the box: agg, wx, wxagg, tkagg, ps, pdf and svg. @@ -99,13 +105,14 @@ http://www.dll-files.com/dllindex/dll-files.shtml?msvcp71 or other sites. You will need to unzip the archive and drag the dll into :file:`c:\windows\system32`. -All of the GUI backends run on windows, but TkAgg is probably the +All of the GUI backends run on Windows, but TkAgg is probably the best for interactive use from the standard python shell or ipython. -The windows installer (:file:`*.exe`) on the download page contains all the +The Windows installer (:file:`*.exe`) on the download page contains all the code you need to get up and running. However, there are many -examples that are not included in the windows installer. If you -want to try the many demos that come in the matplotlib src -distribution, download the zip file and look in the examples subdir. +examples that are not included in the Windows installer. If you +want to try the many demos that come in the matplotlib source +distribution, download the zip file and look in the :file:`examples` +subdirectory. .. _install_from_source: @@ -121,8 +128,7 @@ you want to develop matplotlib or just need the latest bugfixed version, grab the latest git version :ref:`install-from-git`. Once you have satisfied the requirements detailed below (mainly -python, numpy, libpng and freetype), you build matplotlib in the usual -way:: +python, numpy, libpng and freetype), you can build matplotlib:: cd matplotlib python setup.py build @@ -130,8 +136,8 @@ way:: We provide a `setup.cfg `_ -file that lives along :file:`setup.py` which you can use to customize -the build process, for example, which default backend to use, whether +file that goes with :file:`setup.py` which you can use to customize +the build process. For example, which default backend to use, whether some of the optional libraries that matplotlib ships with are installed, and so on. This file will be particularly useful to those packaging matplotlib. @@ -150,10 +156,10 @@ Build requirements These are external packages which you will need to install before installing matplotlib. Windows users only need the first two (python -and numpy) since the others are built into the matplotlib windows +and numpy) since the others are built into the matplotlib Windows installers available for download at the sourceforge site. If you are building on OSX, see :ref:`build_osx`. If you are installing -dependencies with a package manager, you may need to install the +dependencies with a package manager on Linux, you may need to install the development packages (look for a "-dev" postfix) in addition to the libraries themselves. @@ -183,8 +189,8 @@ libraries themselves. libpng 1.2 (or later) library for loading and saving :term:`PNG` files (`download `__). libpng requires - zlib. If you are a windows user, you can ignore this since we - build support into the matplotlib single click installer + zlib. If you are a Windows user, you can ignore this because we + build support into the matplotlib single-click installer :term:`freetype` 1.4 (or later) library for reading true type font files. If you are a windows @@ -196,7 +202,7 @@ libpng 1.2 (or later) These are optional packages which you may want to install to use matplotlib with a user interface toolkit. See :ref:`what-is-a-backend` for more details on the optional matplotlib -backends and the capabilities they provide +backends and the capabilities they provide. :term:`tk` 8.3 or later The TCL/Tk widgets library used by the TkAgg backend @@ -243,13 +249,9 @@ Building on OSX =============== The build situation on OSX is complicated by the various places one -can get the png and freetype requirements from (darwinports, fink, -/usr/X11R6) and the different architectures (x86, ppc, universal) and -the different OSX version (10.4 and 10.5). We recommend that you build -the way we do for the OSX release: by grabbing the tarbar or git -repository, cd-ing into the release/osx dir, and following the -instruction in the README. This directory has a Makefile which will -automatically grab the zlib, png and freetype dependencies from the -web, build them with the right flags to make universal libraries, and -then build the matplotlib source and binary installers. +can get the libpng and freetype requirements (darwinports, fink, +/usr/X11R6) and the different architectures (e.g., x86, ppc, universal) and +the different OSX version (e.g., 10.4 and 10.5). We recommend that you build +the way we do for the OSX release: get the source from the tarball or the +git repository and follow the instruction in :file:`README.osx`. diff --git a/doc/make.py b/doc/make.py index c85d380f8a7b..243d431dc442 100755 --- a/doc/make.py +++ b/doc/make.py @@ -180,7 +180,8 @@ def clean(): 'mpl_examples/units/*.png', 'pyplots/tex_demo.png', '_static/matplotlibrc', - '_templates/gallery.html']: + '_templates/gallery.html', + 'users/installing.rst']: for filename in glob.glob(pattern): if os.path.exists(filename): os.remove(filename) From 371471adecd1d127501d311822a6026900152d72 Mon Sep 17 00:00:00 2001 From: Ben Root Date: Fri, 23 Sep 2011 22:15:08 -0500 Subject: [PATCH 169/214] Fixed a few remaining broken ref-links and plot directives. --- doc/faq/howto_faq.rst | 5 +++-- doc/users/license.rst | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/faq/howto_faq.rst b/doc/faq/howto_faq.rst index c3a4d75b7fba..80dc4ff96504 100644 --- a/doc/faq/howto_faq.rst +++ b/doc/faq/howto_faq.rst @@ -425,6 +425,7 @@ desired. You can use separate matplotlib.ticker formatters and locators as desired because the two axes are independent. .. plot:: + import numpy as np import matplotlib.pyplot as plt @@ -611,7 +612,7 @@ There is a good chance you know more about matplotlib usage in some areas, the stuff you do every day, than many of the core developers who wrote most of the documentation. Just pulled your hair out compiling matplotlib for windows? Write a FAQ or a section for the -:ref:`installing` page. Are you a digital signal processing wizard? +:ref:`installing-faq` page. Are you a digital signal processing wizard? Write a tutorial on the signal analysis plotting functions like :func:`~matplotlib.pyplot.xcorr`, :func:`~matplotlib.pyplot.psd` and :func:`~matplotlib.pyplot.specgram`. Do you use matplotlib with @@ -672,7 +673,7 @@ For more on configuring your backend, see Alternatively, you can avoid pylab/pyplot altogether, which will give you a little more control, by calling the API directly as shown in -:ref:`api_examples-agg_oo.py`. +:ref:`api-agg_oo`. You can either generate hardcopy on the filesystem by calling savefig:: diff --git a/doc/users/license.rst b/doc/users/license.rst index c57ad98bf624..882d1ec1b697 100644 --- a/doc/users/license.rst +++ b/doc/users/license.rst @@ -10,7 +10,7 @@ the `PSF `_ license. See the Open Source Initiative `licenses page `_ for details on individual licenses. Non-BSD compatible licenses (eg LGPL) are acceptable in -matplotlib :ref:`toolkits`. For a discussion of the motivations +matplotlib :ref:`toolkits-index`. For a discussion of the motivations behind the licencing choice, see :ref:`license-discussion`. From fa2a019298b67a5bfa5f4d73ddefb208570141f7 Mon Sep 17 00:00:00 2001 From: Paul Ivanov Date: Fri, 23 Sep 2011 23:54:38 -0700 Subject: [PATCH 170/214] added .mailmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now each committer has only one entry in shortlog $ git shortlog -sn 2094 John Hunter 1678 Michael Droettboom 916 Eric Firing 432 Darren Dale 355 Jae-Joon Lee 272 Andrew Straw 263 Steve Chaplin 194 Jouni K. Seppänen 149 Charles Moad 146 Ryan May 124 Ben Root 59 Jeff Whitaker 53 Manuel Metz 48 Norbert Nemec 45 James Evans 42 pkienzle 42 Todd Miller 29 Paul Barret 25 Michiel de Hoon 23 Jochen Voss --- .mailmap | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000000..9adf7d130d6d --- /dev/null +++ b/.mailmap @@ -0,0 +1,7 @@ +John Hunter jdh2358 +Michael Droettboom Michael Droettboom +Jouni K. Seppänen Jouni K. Seppänen +Ben Root Benjamin Root +Michiel de Hoon Michiel de Hoon +Kevin Davies Kevin Davies +Christoph Gohlke cgohlke From 6ada57f7309121f16cf55ead0930e96966599b2f Mon Sep 17 00:00:00 2001 From: Ben Root Date: Sat, 24 Sep 2011 12:13:51 -0500 Subject: [PATCH 171/214] Only set ARCH_FLAGS if it hasn't been set already --- make.osx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.osx b/make.osx index 31fbc925bad2..e9cd02d9876d 100644 --- a/make.osx +++ b/make.osx @@ -8,7 +8,7 @@ PYVERSION=2.6 PYTHON=python${PYVERSION} MACOSX_DEPLOYMENT_TARGET=10.6 OSX_SDK_VER=10.6 -ARCH_FLAGS=-arch i386 -arch x86_64 +ARCH_FLAGS?=-arch i386 -arch x86_64 # Dependency versions and URLs # From b7d49ff7c68a012e5f20e1f5c1bdb22b8c01368c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Seppa=CC=88nen?= Date: Sat, 24 Sep 2011 22:11:22 +0300 Subject: [PATCH 172/214] Upgrade make.osx png and freetype libraries --- make.osx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make.osx b/make.osx index e9cd02d9876d..8e4561ac42c8 100644 --- a/make.osx +++ b/make.osx @@ -16,8 +16,8 @@ ARCH_FLAGS?=-arch i386 -arch x86_64 # but the download URLs are subject to change. ZLIBVERSION=1.2.5 -PNGVERSION=1.5.1 -FREETYPEVERSION=2.4.4 +PNGVERSION=1.5.4 +FREETYPEVERSION=2.4.6 ZLIBFILE=zlib-${ZLIBVERSION}.tar.gz ZLIBDIR=$(basename $(basename ${ZLIBFILE})) From 286688702019830f18a9eb25f7a8ee0c45f28f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Seppa=CC=88nen?= Date: Sat, 24 Sep 2011 22:25:51 +0300 Subject: [PATCH 173/214] Initialize memory in csv roundtrip test --- lib/matplotlib/tests/test_mlab.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/tests/test_mlab.py b/lib/matplotlib/tests/test_mlab.py index 8ff3aec566aa..c985d4cb3b97 100644 --- a/lib/matplotlib/tests/test_mlab.py +++ b/lib/matplotlib/tests/test_mlab.py @@ -13,9 +13,9 @@ def test_colinear_pca(): def test_recarray_csv_roundtrip(): expected = np.recarray((99,), [('x',np.float),('y',np.float),('t',np.float)]) - expected['x'][0] = 1 - expected['y'][1] = 2 - expected['t'][2] = 3 + expected['x'][:] = np.linspace(-1e9, -1, 99) + expected['y'][:] = np.linspace(1, 1e9, 99) + expected['t'][:] = np.linspace(0, 0.01, 99) fd = tempfile.TemporaryFile(suffix='csv') mlab.rec2csv(expected,fd) fd.seek(0) From 5ecc79b4dcdec07e6961ba32983d0ccf5f99fff8 Mon Sep 17 00:00:00 2001 From: cgohlke Date: Sat, 24 Sep 2011 14:38:30 -0700 Subject: [PATCH 174/214] Fix conversion error message --- lib/matplotlib/testing/compare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/testing/compare.py b/lib/matplotlib/testing/compare.py index cf6b33dc6c9f..76ae263d013d 100644 --- a/lib/matplotlib/testing/compare.py +++ b/lib/matplotlib/testing/compare.py @@ -91,7 +91,7 @@ def convert(*args): stdout, stderr = pipe.communicate() errcode = pipe.wait() if not os.path.exists(newname) or errcode: - msg = "Conversion command failed:\n%s\n" % ' '.join(cmd) + msg = "Conversion command failed:\n%s\n" % ' '.join(cmdline) if stdout: msg += "Standard output:\n%s\n" % stdout if stderr: From 0cee09d1f0f7e1a4963a06f23b086483b58b45f0 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Sep 2011 10:28:42 -0400 Subject: [PATCH 175/214] Upgrade PyCXX to version 6.2.4 and pull in all of the changes from the matplotlib-py3 branch. --- CXX/Python2/Exception.hxx | 10 ++ CXX/Python2/ExtensionOldType.hxx | 5 + CXX/Python2/ExtensionType.hxx | 99 +++++++---- CXX/Python2/ExtensionTypeBase.hxx | 32 ++++ CXX/Python2/Objects.hxx | 212 +++++++++++++++++++----- CXX/Python2/cxx_extensions.cxx | 88 +++++++++- CXX/Python3/Exception.hxx | 10 ++ CXX/Python3/ExtensionModule.hxx | 6 +- CXX/Python3/ExtensionOldType.hxx | 13 +- CXX/Python3/ExtensionType.hxx | 99 +++++++---- CXX/Python3/ExtensionTypeBase.hxx | 35 +++- CXX/Python3/IndirectPythonInterface.cxx | 9 - CXX/Python3/IndirectPythonInterface.hxx | 5 - CXX/Python3/Objects.hxx | 158 +++++++++++++++++- CXX/Python3/cxx_extensions.cxx | 141 ++++++++++++++-- CXX/Version.hxx | 4 +- CXX/WrapPython.h | 17 +- 17 files changed, 782 insertions(+), 161 deletions(-) diff --git a/CXX/Python2/Exception.hxx b/CXX/Python2/Exception.hxx index 1ef087cac9fe..3acc0ae4182a 100644 --- a/CXX/Python2/Exception.hxx +++ b/CXX/Python2/Exception.hxx @@ -163,6 +163,16 @@ namespace Py } }; + class NotImplementedError: public StandardError + { + public: + NotImplementedError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_NotImplementedError(), reason.c_str()); + } + }; + class SystemError: public StandardError { public: diff --git a/CXX/Python2/ExtensionOldType.hxx b/CXX/Python2/ExtensionOldType.hxx index 8aa2a3e3cfe7..cfd2fbe6a578 100644 --- a/CXX/Python2/ExtensionOldType.hxx +++ b/CXX/Python2/ExtensionOldType.hxx @@ -74,6 +74,11 @@ namespace Py return this; } + Object self() + { + return asObject( this ); + } + protected: explicit PythonExtension() : PythonExtensionBase() diff --git a/CXX/Python2/ExtensionType.hxx b/CXX/Python2/ExtensionType.hxx index 2b41dbbf9701..4128960eea2a 100644 --- a/CXX/Python2/ExtensionType.hxx +++ b/CXX/Python2/ExtensionType.hxx @@ -45,44 +45,67 @@ #define PYCXX_NOARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_NOARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *, PyObject * ) \ { \ - Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ - CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ - Py::Object r( (self->NAME)() ); \ - return Py::new_reference_to( r.ptr() ); \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Object r( (self->NAME)() ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::Exception & ) \ + { \ + return 0; \ + } \ } #define PYCXX_VARARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_VARARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject * ) \ { \ - Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ - CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ - Py::Tuple a( _a ); \ - Py::Object r( (self->NAME)( a ) ); \ - return Py::new_reference_to( r.ptr() ); \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Tuple a( _a ); \ + Py::Object r( (self->NAME)( a ) ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::Exception & ) \ + { \ + return 0; \ + } \ } #define PYCXX_KEYWORDS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_KEYWORDS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject *_k ) \ { \ - Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ - CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ - Py::Tuple a( _a ); \ - Py::Dict k; \ - if( _k != NULL ) \ - k = _k; \ - Py::Object r( (self->NAME)( a, k ) ); \ - return Py::new_reference_to( r.ptr() ); \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Tuple a( _a ); \ + Py::Dict k; \ + if( _k != NULL ) \ + k = _k; \ + Py::Object r( (self->NAME)( a, k ) ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::Exception & ) \ + { \ + return 0; \ + } \ } // need to support METH_STATIC and METH_CLASS -#define PYCXX_ADD_NOARGS_METHOD( NAME, docs ) \ - add_method( #NAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) -#define PYCXX_ADD_VARARGS_METHOD( NAME, docs ) \ - add_method( #NAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) -#define PYCXX_ADD_KEYWORDS_METHOD( NAME, docs ) \ - add_method( #NAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) +#define PYCXX_ADD_NOARGS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) +#define PYCXX_ADD_VARARGS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) +#define PYCXX_ADD_KEYWORDS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) namespace Py { + extern PythonExtensionBase *getPythonExtensionBase( PyObject *self ); + struct PythonClassInstance { PyObject_HEAD @@ -131,7 +154,7 @@ namespace Py { new_mt[ i ] = old_mt[ i ]; } - delete old_mt; + delete[] old_mt; m_methods_table = new_mt; } @@ -167,10 +190,8 @@ namespace Py protected: explicit PythonClass( PythonClassInstance *self, Tuple &args, Dict &kwds ) : PythonExtensionBase() - , m_self( self ) + , m_class_instance( self ) { - // we are a class - behaviors().supportClass(); } virtual ~PythonClass() @@ -203,6 +224,12 @@ namespace Py p->set_tp_new( extension_object_new ); p->set_tp_init( extension_object_init ); p->set_tp_dealloc( extension_object_deallocator ); + // we are a class + p->supportClass(); + + // always support get and set attr + p->supportGetattro(); + p->supportSetattro(); } return *p; @@ -238,7 +265,7 @@ namespace Py PythonClassInstance *self = reinterpret_cast( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_init( self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << " )" << std::endl; - std::cout << " self->cxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->cxx_object ) << std::dec << std::endl; + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl; #endif if( self->m_pycxx_object == NULL ) @@ -268,9 +295,10 @@ namespace Py PythonClassInstance *self = reinterpret_cast< PythonClassInstance * >( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_deallocator( self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << " )" << std::endl; - std::cout << " self->cxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->cxx_object ) << std::dec << std::endl; + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl; #endif delete self->m_pycxx_object; + _self->ob_type->tp_free( _self ); } public: @@ -295,14 +323,19 @@ namespace Py return check( ob.ptr() ); } - PyObject *selfPtr() + virtual PyObject *selfPtr() + { + return reinterpret_cast( m_class_instance ); + } + + virtual Object self() { - return reinterpret_cast( m_self ); + return Object( reinterpret_cast( m_class_instance ) ); } protected: private: - PythonClassInstance *m_self; + PythonClassInstance *m_class_instance; private: // @@ -361,7 +394,7 @@ namespace Py // T *getCxxObject( void ) { - return static_cast( ptr() ); + return dynamic_cast< T * >( getPythonExtensionBase( ptr() ) ); } }; } // Namespace Py diff --git a/CXX/Python2/ExtensionTypeBase.hxx b/CXX/Python2/ExtensionTypeBase.hxx index eaebe650b629..ad11029e71dc 100644 --- a/CXX/Python2/ExtensionTypeBase.hxx +++ b/CXX/Python2/ExtensionTypeBase.hxx @@ -131,8 +131,40 @@ namespace Py virtual Py_ssize_t buffer_getwritebuffer( Py_ssize_t, void** ); virtual Py_ssize_t buffer_getsegcount( Py_ssize_t* ); + public: + // helper functions to call function fn_name with 0 to 9 args + Object callOnSelf( const std::string &fn_name ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8, const Object &arg9 ); + public: virtual PyObject *selfPtr() = 0; + virtual Object self() = 0; private: void missing_method( void ); diff --git a/CXX/Python2/Objects.hxx b/CXX/Python2/Objects.hxx index ce1fa98f249a..286293ead71a 100644 --- a/CXX/Python2/Objects.hxx +++ b/CXX/Python2/Objects.hxx @@ -61,6 +61,8 @@ namespace Py class String; class List; template class MapBase; + class Tuple; + class Dict; // new_reference_to also overloaded below on Object inline PyObject* new_reference_to(PyObject* p) @@ -268,6 +270,10 @@ namespace Py return Object (PyObject_GetAttrString (p, const_cast(s.c_str())), true); } + Object callMemberFunction( const std::string &function_name ) const; + Object callMemberFunction( const std::string &function_name, const Tuple &args ) const; + Object callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const; + Object getItem (const Object& key) const { return Object (PyObject_GetItem(p, *key), true); @@ -1718,7 +1724,6 @@ namespace Py template bool operator<=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); template bool operator>=(const EXPLICIT_TYPENAME SeqBase::const_iterator& left, const EXPLICIT_TYPENAME SeqBase::const_iterator& right); - extern bool operator==(const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator!=(const Sequence::iterator& left, const Sequence::iterator& right); extern bool operator< (const Sequence::iterator& left, const Sequence::iterator& right); @@ -1848,62 +1853,61 @@ namespace Py } String() - : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) + : SeqBase( PyString_FromStringAndSize( "", 0 ), true ) { validate(); } String( const std::string& v ) - : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), + : SeqBase( PyString_FromStringAndSize( const_cast(v.data()), static_cast( v.length() ) ), true ) { validate(); } - String( const char *s, const char *encoding, const char *error="strict" ) - : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) + String( const Py_UNICODE *s, int length ) + : SeqBase( PyUnicode_FromUnicode( s, length ), true ) { validate(); } - String( const char *s, int len, const char *encoding, const char *error="strict" ) - : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) + String( const char *s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, strlen( s ), encoding, error ), true ) { validate(); } - String( const std::string &s, const char *encoding, const char *error="strict" ) - : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) + String( const char *s, int len, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s, len, encoding, error ), true ) { validate(); } - String( const std::string& v, std::string::size_type vsize ) - : SeqBase(PyString_FromStringAndSize( const_cast(v.data()), - static_cast( vsize ) ), true) + String( const std::string &s, const char *encoding, const char *error="strict" ) + : SeqBase( PyUnicode_Decode( s.c_str(), s.length(), encoding, error ), true ) { validate(); } String( const char *v, int vsize ) - : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) + : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { validate(); } - String( const char* v ) - : SeqBase( PyString_FromString( v ), true ) + String( const char *v ) + : SeqBase( PyString_FromString( v ), true ) { validate(); } // Assignment acquires new ownership of pointer - String& operator= ( const Object& rhs ) + String &operator=( const Object &rhs ) { return *this = *rhs; } - String& operator= (PyObject* rhsp) + String& operator= (PyObject *rhsp) { if( ptr() == rhsp ) return *this; @@ -1917,25 +1921,24 @@ namespace Py } // Assignment from C string - String& operator= (const std::string& v) + String& operator=( const std::string &v ) { set( PyString_FromStringAndSize( const_cast( v.data() ), static_cast( v.length() ) ), true ); return *this; } - String& operator= (const unicodestring& v) + String& operator=( const unicodestring &v ) { set( PyUnicode_FromUnicode( const_cast( v.data() ), static_cast( v.length() ) ), true ); return *this; } - // Encode Bytes encode( const char *encoding, const char *error="strict" ) const; // Queries - virtual size_type size () const + virtual size_type size() const { if( isUnicode() ) { @@ -1947,7 +1950,7 @@ namespace Py } } - operator std::string () const + operator std::string() const { return as_std_string( "utf-8" ); } @@ -1966,6 +1969,18 @@ namespace Py throw TypeError("can only return unicodestring from Unicode object"); } } + + const Py_UNICODE *unicode_data() const + { + if( isUnicode() ) + { + return PyUnicode_AS_UNICODE( ptr() ); + } + else + { + throw TypeError("can only return unicode_data from Unicode object"); + } + } }; class Bytes: public SeqBase { @@ -1997,12 +2012,6 @@ namespace Py validate(); } - Bytes( const std::string& v, std::string::size_type vsize ) - : SeqBase(PyString_FromStringAndSize( const_cast(v.data()), static_cast( vsize ) ), true) - { - validate(); - } - Bytes( const char *v, int vsize ) : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { @@ -2050,7 +2059,7 @@ namespace Py String decode( const char *encoding, const char *error="strict" ) { - return Object( PyString_AsDecodedObject( ptr(), encoding, error ) ); + return Object( PyString_AsDecodedObject( ptr(), encoding, error ), true ); } // Queries @@ -2148,13 +2157,6 @@ namespace Py validate(); } - String( const std::string& v, std::string::size_type vsize ) - : SeqBase(PyString_FromStringAndSize( const_cast(v.data()), - static_cast( vsize ) ), true) - { - validate(); - } - String( const char *v, int vsize ) : SeqBase(PyString_FromStringAndSize( const_cast(v), vsize ), true ) { @@ -2206,17 +2208,17 @@ namespace Py { if( isUnicode() ) { - return String( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); + return String( PyUnicode_AsEncodedString( ptr(), encoding, error ), true ); } else { - return String( PyString_AsEncodedObject( ptr(), encoding, error ) ); + return String( PyString_AsEncodedObject( ptr(), encoding, error ), true ); } } String decode( const char *encoding, const char *error="strict" ) { - return Object( PyString_AsDecodedObject( ptr(), encoding, error ) ); + return Object( PyString_AsDecodedObject( ptr(), encoding, error ), true ); } // Queries @@ -2346,6 +2348,118 @@ namespace Py }; + class TupleN: public Tuple + { + public: + TupleN() + : Tuple( 0 ) + { + } + + TupleN( const Object &obj1 ) + : Tuple( 1 ) + { + setItem( 0, obj1 ); + } + + TupleN( const Object &obj1, const Object &obj2 ) + : Tuple( 2 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3 ) + : Tuple( 3 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4 ) + : Tuple( 4 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5 ) + : Tuple( 5 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6 ) + : Tuple( 6 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7 ) + : Tuple( 7 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7, const Object &obj8 ) + : Tuple( 8 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + setItem( 7, obj8 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7, const Object &obj8, const Object &obj9 ) + : Tuple( 9 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + setItem( 7, obj8 ); + setItem( 8, obj9 ); + } + + virtual ~TupleN() + { } + }; + + // ================================================== // class List @@ -3154,6 +3268,26 @@ namespace Py } }; + // Call function helper + inline Object Object::callMemberFunction( const std::string &function_name ) const + { + Callable target( getAttr( function_name ) ); + Tuple args( 0 ); + return target.apply( args ); + } + + inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args ) const + { + Callable target( getAttr( function_name ) ); + return target.apply( args ); + } + + inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const + { + Callable target( getAttr( function_name ) ); + return target.apply( args, kw ); + } + // Numeric interface inline Object operator+ (const Object& a) { diff --git a/CXX/Python2/cxx_extensions.cxx b/CXX/Python2/cxx_extensions.cxx index 2c39dfd064de..0e0ade093e27 100644 --- a/CXX/Python2/cxx_extensions.cxx +++ b/CXX/Python2/cxx_extensions.cxx @@ -1320,6 +1320,84 @@ PythonExtensionBase::~PythonExtensionBase() assert( ob_refcnt == 0 ); } +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name ) +{ + Py::TupleN args; + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1 ) +{ + Py::TupleN args( arg1 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2 ) +{ + Py::TupleN args( arg1, arg2 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3 ) +{ + Py::TupleN args( arg1, arg2, arg3 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6, + const Py::Object &arg7 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6, + const Py::Object &arg7, const Py::Object &arg8 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6, + const Py::Object &arg7, const Py::Object &arg8, const Py::Object &arg9 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); + return self().callMemberFunction( fn_name, args ); +} + void PythonExtensionBase::reinit( Tuple &args, Dict &kwds ) { throw RuntimeError( "Must not call __init__ twice on this class" ); @@ -1353,16 +1431,14 @@ int PythonExtensionBase::setattr( const char *, const Py::Object &) return -1; } -Py::Object PythonExtensionBase::getattro( const Py::String &) +Py::Object PythonExtensionBase::getattro( const Py::String &name ) { - missing_method( getattro ); - return Py::None(); + return genericGetAttro( name ); } -int PythonExtensionBase::setattro( const Py::String &, const Py::Object &) +int PythonExtensionBase::setattro( const Py::String &name, const Py::Object &value ) { - missing_method( setattro ); - return -1; + return genericSetAttro( name, value ); } int PythonExtensionBase::compare( const Py::Object &) diff --git a/CXX/Python3/Exception.hxx b/CXX/Python3/Exception.hxx index 07908d1ef4b2..0bd052d5cc7d 100644 --- a/CXX/Python3/Exception.hxx +++ b/CXX/Python3/Exception.hxx @@ -164,6 +164,16 @@ namespace Py } }; + class NotImplementedError: public StandardError + { + public: + NotImplementedError (const std::string& reason) + : StandardError() + { + PyErr_SetString (Py::_Exc_NotImplementedError(), reason.c_str()); + } + }; + class SystemError: public StandardError { public: diff --git a/CXX/Python3/ExtensionModule.hxx b/CXX/Python3/ExtensionModule.hxx index b41decc821c5..a892a6f8cde5 100644 --- a/CXX/Python3/ExtensionModule.hxx +++ b/CXX/Python3/ExtensionModule.hxx @@ -82,8 +82,6 @@ namespace Py extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple, PyObject *_args ); extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple, PyObject *_args, PyObject *_keywords ); - extern "C" void do_not_dealloc( void * ); - template class ExtensionModule : public ExtensionModuleBase { @@ -134,11 +132,11 @@ namespace Py { MethodDefExt *method_def = (*i).second; - static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); + static PyObject *self = PyCapsule_New( this, NULL, NULL ); Tuple args( 2 ); args[0] = Object( self ); - args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) ); + args[1] = Object( PyCapsule_New( method_def, NULL, NULL ) ); PyObject *func = PyCFunction_New ( diff --git a/CXX/Python3/ExtensionOldType.hxx b/CXX/Python3/ExtensionOldType.hxx index 56e6af2ecbfd..355dcfb220bb 100644 --- a/CXX/Python3/ExtensionOldType.hxx +++ b/CXX/Python3/ExtensionOldType.hxx @@ -74,6 +74,11 @@ namespace Py return this; } + Object self() + { + return asObject( this ); + } + protected: explicit PythonExtension() : PythonExtensionBase() @@ -173,7 +178,7 @@ namespace Py Tuple self( 2 ); self[0] = Object( this ); - self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) ); + self[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); PyObject *func = PyCFunction_New( &method_def->ext_meth_def, self.ptr() ); @@ -232,7 +237,7 @@ namespace Py T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ); Object result; @@ -268,7 +273,7 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ); Tuple args( _args ); @@ -305,7 +310,7 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); MethodDefExt *meth_def = reinterpret_cast *>( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ); Tuple args( _args ); diff --git a/CXX/Python3/ExtensionType.hxx b/CXX/Python3/ExtensionType.hxx index c1b8721e4357..df680dbdfe15 100644 --- a/CXX/Python3/ExtensionType.hxx +++ b/CXX/Python3/ExtensionType.hxx @@ -45,44 +45,66 @@ #define PYCXX_NOARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_NOARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *, PyObject * ) \ { \ - Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ - CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ - Py::Object r( (self->NAME)() ); \ - return Py::new_reference_to( r.ptr() ); \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Object r( (self->NAME)() ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::Exception & ) \ + { \ + return 0; \ + } \ } #define PYCXX_VARARGS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_VARARGS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject * ) \ { \ - Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ - CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ - Py::Tuple a( _a ); \ - Py::Object r( (self->NAME)( a ) ); \ - return Py::new_reference_to( r.ptr() ); \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Tuple a( _a ); \ + Py::Object r( (self->NAME)( a ) ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::Exception & ) \ + { \ + return 0; \ + } \ } #define PYCXX_KEYWORDS_METHOD_DECL( CLS, NAME ) \ static PyObject *PYCXX_KEYWORDS_METHOD_NAME( NAME )( PyObject *_self, PyObject *_a, PyObject *_k ) \ { \ - Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ - CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ - Py::Tuple a( _a ); \ - Py::Dict k; \ - if( _k != NULL ) \ - k = _k; \ - Py::Object r( (self->NAME)( a, k ) ); \ - return Py::new_reference_to( r.ptr() ); \ + try \ + { \ + Py::PythonClassInstance *self_python = reinterpret_cast< Py::PythonClassInstance * >( _self ); \ + CLS *self = reinterpret_cast< CLS * >( self_python->m_pycxx_object ); \ + Py::Tuple a( _a ); \ + Py::Dict k; \ + if( _k != NULL ) \ + k = _k; \ + Py::Object r( (self->NAME)( a, k ) ); \ + return Py::new_reference_to( r.ptr() ); \ + } \ + catch( Py::Exception & ) \ + { \ + return 0; \ + } \ } // need to support METH_STATIC and METH_CLASS -#define PYCXX_ADD_NOARGS_METHOD( NAME, docs ) \ - add_method( #NAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) -#define PYCXX_ADD_VARARGS_METHOD( NAME, docs ) \ - add_method( #NAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) -#define PYCXX_ADD_KEYWORDS_METHOD( NAME, docs ) \ - add_method( #NAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) +#define PYCXX_ADD_NOARGS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_NOARGS_METHOD_NAME( NAME ), METH_NOARGS, docs ) +#define PYCXX_ADD_VARARGS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_VARARGS_METHOD_NAME( NAME ), METH_VARARGS, docs ) +#define PYCXX_ADD_KEYWORDS_METHOD( PYNAME, NAME, docs ) \ + add_method( #PYNAME, (PyCFunction)PYCXX_KEYWORDS_METHOD_NAME( NAME ), METH_VARARGS | METH_KEYWORDS, docs ) namespace Py { + extern PythonExtensionBase *getPythonExtensionBase( PyObject *self ); struct PythonClassInstance { PyObject_HEAD @@ -131,7 +153,7 @@ namespace Py { new_mt[ i ] = old_mt[ i ]; } - delete old_mt; + delete[] old_mt; m_methods_table = new_mt; } @@ -167,10 +189,8 @@ namespace Py protected: explicit PythonClass( PythonClassInstance *self, Tuple &args, Dict &kwds ) : PythonExtensionBase() - , m_self( self ) + , m_class_instance( self ) { - // we are a class - behaviors().supportClass(); } virtual ~PythonClass() @@ -203,6 +223,13 @@ namespace Py p->set_tp_new( extension_object_new ); p->set_tp_init( extension_object_init ); p->set_tp_dealloc( extension_object_deallocator ); + + // we are a class + p->supportClass(); + + // always support get and set attr + p->supportGetattro(); + p->supportSetattro(); } return *p; @@ -238,7 +265,7 @@ namespace Py PythonClassInstance *self = reinterpret_cast( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_init( self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << " )" << std::endl; - std::cout << " self->cxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->cxx_object ) << std::dec << std::endl; + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl; #endif if( self->m_pycxx_object == NULL ) @@ -268,9 +295,10 @@ namespace Py PythonClassInstance *self = reinterpret_cast< PythonClassInstance * >( _self ); #ifdef PYCXX_DEBUG std::cout << "extension_object_deallocator( self=0x" << std::hex << reinterpret_cast< unsigned int >( self ) << std::dec << " )" << std::endl; - std::cout << " self->cxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->cxx_object ) << std::dec << std::endl; + std::cout << " self->m_pycxx_object=0x" << std::hex << reinterpret_cast< unsigned int >( self->m_pycxx_object ) << std::dec << std::endl; #endif delete self->m_pycxx_object; + _self->ob_type->tp_free( _self ); } public: @@ -295,14 +323,19 @@ namespace Py return check( ob.ptr() ); } - PyObject *selfPtr() + virtual PyObject *selfPtr() + { + return reinterpret_cast( m_class_instance ); + } + + virtual Object self() { - return reinterpret_cast( m_self ); + return Object( reinterpret_cast( m_class_instance ) ); } protected: private: - PythonClassInstance *m_self; + PythonClassInstance *m_class_instance; private: // @@ -361,7 +394,7 @@ namespace Py // T *getCxxObject( void ) { - return static_cast( ptr() ); + return dynamic_cast< T * >( getPythonExtensionBase( ptr() ) ); } }; } // Namespace Py diff --git a/CXX/Python3/ExtensionTypeBase.hxx b/CXX/Python3/ExtensionTypeBase.hxx index 5b83b033a7ff..3936ccc28801 100644 --- a/CXX/Python3/ExtensionTypeBase.hxx +++ b/CXX/Python3/ExtensionTypeBase.hxx @@ -121,10 +121,43 @@ namespace Py virtual Object number_power( const Object &, const Object & ); // Buffer - // QQQ need to add py3 interface + virtual int buffer_get( Py_buffer *, int flags ); + virtual int buffer_release( Py_buffer *buf ); + + public: + // helper functions to call function fn_name with 0 to 9 args + Object callOnSelf( const std::string &fn_name ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8 ); + Object callOnSelf( const std::string &fn_name, + const Object &arg1, const Object &arg2, const Object &arg3, + const Object &arg4, const Object &arg5, const Object &arg6, + const Object &arg7, const Object &arg8, const Object &arg9 ); public: virtual PyObject *selfPtr() = 0; + virtual Object self() = 0; private: void missing_method( void ); diff --git a/CXX/Python3/IndirectPythonInterface.cxx b/CXX/Python3/IndirectPythonInterface.cxx index 28784fd532c0..2b7ff41b75da 100644 --- a/CXX/Python3/IndirectPythonInterface.cxx +++ b/CXX/Python3/IndirectPythonInterface.cxx @@ -40,7 +40,6 @@ namespace Py { bool _CFunction_Check( PyObject *op ) { return op->ob_type == _CFunction_Type(); } -bool _CObject_Check( PyObject *op ) { return op->ob_type == _CObject_Type(); } bool _Complex_Check( PyObject *op ) { return op->ob_type == _Complex_Type(); } bool _Dict_Check( PyObject *op ) { return op->ob_type == _Dict_Type(); } bool _Float_Check( PyObject *op ) { return op->ob_type == _Float_Type(); } @@ -80,7 +79,6 @@ static PyObject *ptr__Exc_KeyboardInterrupt = NULL; static PyObject *ptr__Exc_KeyError = NULL; static PyObject *ptr__Exc_LookupError = NULL; static PyObject *ptr__Exc_MemoryError = NULL; -static PyObject *ptr__Exc_MemoryErrorInst = NULL; static PyObject *ptr__Exc_NameError = NULL; static PyObject *ptr__Exc_NotImplementedError = NULL; static PyObject *ptr__Exc_OSError = NULL; @@ -106,7 +104,6 @@ static PyObject *ptr__PyNone = NULL; static PyObject *ptr__PyFalse = NULL; static PyObject *ptr__PyTrue = NULL; static PyTypeObject *ptr__CFunction_Type = NULL; -static PyTypeObject *ptr__CObject_Type = NULL; static PyTypeObject *ptr__Complex_Type = NULL; static PyTypeObject *ptr__Dict_Type = NULL; static PyTypeObject *ptr__Float_Type = NULL; @@ -245,7 +242,6 @@ bool InitialisePythonIndirectInterface() ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); - ptr__Exc_MemoryErrorInst = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryErrorInst" ); ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); ptr__Exc_NotImplementedError= GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); @@ -271,7 +267,6 @@ bool InitialisePythonIndirectInterface() ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); - ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); @@ -318,7 +313,6 @@ PyObject *_Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } PyObject *_Exc_KeyError() { return ptr__Exc_KeyError; } PyObject *_Exc_LookupError() { return ptr__Exc_LookupError; } PyObject *_Exc_MemoryError() { return ptr__Exc_MemoryError; } -PyObject *_Exc_MemoryErrorInst() { return ptr__Exc_MemoryErrorInst; } PyObject *_Exc_NameError() { return ptr__Exc_NameError; } PyObject *_Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } PyObject *_Exc_OSError() { return ptr__Exc_OSError; } @@ -348,7 +342,6 @@ PyObject *_False() { return ptr__PyFalse; } PyObject *_True() { return ptr__PyTrue; } PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } -PyTypeObject *_CObject_Type() { return ptr__CObject_Type; } PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } PyTypeObject *_Float_Type() { return ptr__Float_Type; } @@ -449,7 +442,6 @@ PyObject *_Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } PyObject *_Exc_KeyError() { return ::PyExc_KeyError; } PyObject *_Exc_LookupError() { return ::PyExc_LookupError; } PyObject *_Exc_MemoryError() { return ::PyExc_MemoryError; } -PyObject *_Exc_MemoryErrorInst() { return ::PyExc_MemoryErrorInst; } PyObject *_Exc_NameError() { return ::PyExc_NameError; } PyObject *_Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } PyObject *_Exc_OSError() { return ::PyExc_OSError; } @@ -482,7 +474,6 @@ PyObject *_False() { return Py_False; } PyObject *_True() { return Py_True; } PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } -PyTypeObject *_CObject_Type() { return &PyCObject_Type; } PyTypeObject *_Complex_Type() { return &PyComplex_Type; } PyTypeObject *_Dict_Type() { return &PyDict_Type; } PyTypeObject *_Float_Type() { return &PyFloat_Type; } diff --git a/CXX/Python3/IndirectPythonInterface.hxx b/CXX/Python3/IndirectPythonInterface.hxx index fed8e3c2a18f..cdae3ad35e75 100644 --- a/CXX/Python3/IndirectPythonInterface.hxx +++ b/CXX/Python3/IndirectPythonInterface.hxx @@ -78,8 +78,6 @@ PyObject * _Exc_ZeroDivisionError(); PyObject * _Exc_WindowsError(); #endif -PyObject * _Exc_MemoryErrorInst(); - PyObject * _Exc_IndentationError(); PyObject * _Exc_TabError(); PyObject * _Exc_UnboundLocalError(); @@ -111,9 +109,6 @@ bool _Instance_Check( PyObject *op ); PyTypeObject * _Method_Type(); bool _Method_Check( PyObject *op ); -PyTypeObject * _CObject_Type(); -bool _CObject_Check( PyObject *op ); - PyTypeObject * _Complex_Type(); bool _Complex_Check( PyObject *op ); diff --git a/CXX/Python3/Objects.hxx b/CXX/Python3/Objects.hxx index 4ed1a7c00ce4..96f824c8ffc4 100644 --- a/CXX/Python3/Objects.hxx +++ b/CXX/Python3/Objects.hxx @@ -63,6 +63,8 @@ namespace Py class String; class List; template class MapBase; + class Tuple; + class Dict; //===========================================================================// // class Object @@ -265,6 +267,10 @@ namespace Py return Object( PyObject_GetAttrString( p, const_cast( s.c_str() ) ), true ); } + Object callMemberFunction( const std::string &function_name ) const; + Object callMemberFunction( const std::string &function_name, const Tuple &args ) const; + Object callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const; + Object getItem( const Object &key ) const { return Object( PyObject_GetItem( p, *key ), true ); @@ -2012,7 +2018,7 @@ namespace Py } String() - : SeqBase( PyUnicode_FromString( "" ), true ) + : SeqBase( PyUnicode_FromString( "" ) ) { validate(); } @@ -2053,19 +2059,25 @@ namespace Py */ String( const std::string &s, const char *encoding, const char *errors=NULL ) - : SeqBase( PyUnicode_Decode( s.c_str(), s.size(), encoding, errors ) ) + : SeqBase( PyUnicode_Decode( s.c_str(), s.size(), encoding, errors ), true ) { validate(); } String( const char *s, const char *encoding, const char *errors=NULL ) - : SeqBase( PyUnicode_Decode( s, strlen(s), encoding, errors ) ) + : SeqBase( PyUnicode_Decode( s, strlen(s), encoding, errors ), true ) { validate(); } String( const char *s, Py_ssize_t size, const char *encoding, const char *errors=NULL ) - : SeqBase( PyUnicode_Decode( s, size, encoding, errors ) ) + : SeqBase( PyUnicode_Decode( s, size, encoding, errors ), true ) + { + validate(); + } + + String( const Py_UNICODE *s, int length ) + : SeqBase( PyUnicode_FromUnicode( s, length ), true ) { validate(); } @@ -2092,7 +2104,7 @@ namespace Py // Encode Bytes encode( const char *encoding, const char *error="strict" ) const { - return Bytes( PyUnicode_AsEncodedString( ptr(), encoding, error ) ); + return Bytes( PyUnicode_AsEncodedString( ptr(), encoding, error ), true ); } // Queries @@ -2117,6 +2129,11 @@ namespace Py Bytes b( encode( encoding, error ) ); return b.as_std_string(); } + + const Py_UNICODE *unicode_data() const + { + return PyUnicode_AS_UNICODE( ptr() ); + } }; // ================================================== @@ -2201,6 +2218,117 @@ namespace Py }; + class TupleN: public Tuple + { + public: + TupleN() + : Tuple( 0 ) + { + } + + TupleN( const Object &obj1 ) + : Tuple( 1 ) + { + setItem( 0, obj1 ); + } + + TupleN( const Object &obj1, const Object &obj2 ) + : Tuple( 2 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3 ) + : Tuple( 3 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4 ) + : Tuple( 4 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5 ) + : Tuple( 5 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6 ) + : Tuple( 6 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7 ) + : Tuple( 7 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7, const Object &obj8 ) + : Tuple( 8 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + setItem( 7, obj8 ); + } + + TupleN( const Object &obj1, const Object &obj2, const Object &obj3, + const Object &obj4, const Object &obj5, const Object &obj6, + const Object &obj7, const Object &obj8, const Object &obj9 ) + : Tuple( 9 ) + { + setItem( 0, obj1 ); + setItem( 1, obj2 ); + setItem( 2, obj3 ); + setItem( 3, obj4 ); + setItem( 4, obj5 ); + setItem( 5, obj6 ); + setItem( 6, obj7 ); + setItem( 7, obj8 ); + setItem( 8, obj9 ); + } + + virtual ~TupleN() + { } + }; + // ================================================== // class List @@ -3067,6 +3195,26 @@ namespace Py } }; + // Call function helper + inline Object Object::callMemberFunction( const std::string &function_name ) const + { + Callable target( getAttr( function_name ) ); + Tuple args( 0 ); + return target.apply( args ); + } + + inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args ) const + { + Callable target( getAttr( function_name ) ); + return target.apply( args ); + } + + inline Object Object::callMemberFunction( const std::string &function_name, const Tuple &args, const Dict &kw ) const + { + Callable target( getAttr( function_name ) ); + return target.apply( args, kw ); + } + // Numeric interface inline Object operator+( const Object &a ) { diff --git a/CXX/Python3/cxx_extensions.cxx b/CXX/Python3/cxx_extensions.cxx index c7f42bd9a927..b6e3aa083d0b 100644 --- a/CXX/Python3/cxx_extensions.cxx +++ b/CXX/Python3/cxx_extensions.cxx @@ -262,7 +262,8 @@ extern "C" static PyObject *number_power_handler( PyObject *, PyObject *, PyObject * ); // Buffer - // QQQ + static int buffer_get_handler( PyObject *, Py_buffer *, int ); + static void buffer_release_handler( PyObject *, Py_buffer * ); } extern "C" void standard_dealloc( PyObject *p ) @@ -345,8 +346,8 @@ PythonType &PythonType::supportBufferType() buffer_table = new PyBufferProcs; memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 table->tp_as_buffer = buffer_table; - // QQQ bf_getbuffer - // QQQ bf_releasebuffer + buffer_table->bf_getbuffer = buffer_get_handler; + buffer_table->bf_releasebuffer = buffer_release_handler; } return *this; } @@ -1099,6 +1100,25 @@ extern "C" PyObject *number_power_handler( PyObject *self, PyObject *x1, PyObjec } // Buffer +extern "C" int buffer_get_handler( PyObject *self, Py_buffer *buf, int flags ) +{ + try + { + PythonExtensionBase *p = getPythonExtensionBase( self ); + return p->buffer_get( buf, flags ); + } + catch( Py::Exception & ) + { + return -1; // indicate error + } +} + +extern "C" void buffer_release_handler( PyObject *self, Py_buffer *buf ) +{ + PythonExtensionBase *p = getPythonExtensionBase( self ); + p->buffer_release( buf ); + // NOTE: No way to indicate error to Python +} //================================================================================ // @@ -1118,6 +1138,84 @@ PythonExtensionBase::~PythonExtensionBase() assert( ob_refcnt == 0 ); } +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name ) +{ + Py::TupleN args; + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1 ) +{ + Py::TupleN args( arg1 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2 ) +{ + Py::TupleN args( arg1, arg2 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3 ) +{ + Py::TupleN args( arg1, arg2, arg3 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6, + const Py::Object &arg7 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6, + const Py::Object &arg7, const Py::Object &arg8 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 ); + return self().callMemberFunction( fn_name, args ); +} + +Py::Object PythonExtensionBase::callOnSelf( const std::string &fn_name, + const Py::Object &arg1, const Py::Object &arg2, const Py::Object &arg3, + const Py::Object &arg4, const Py::Object &arg5, const Py::Object &arg6, + const Py::Object &arg7, const Py::Object &arg8, const Py::Object &arg9 ) +{ + Py::TupleN args( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 ); + return self().callMemberFunction( fn_name, args ); +} + void PythonExtensionBase::reinit( Tuple &args, Dict &kwds ) { throw RuntimeError( "Must not call __init__ twice on this class" ); @@ -1154,16 +1252,14 @@ int PythonExtensionBase::setattr( const char *, const Py::Object & ) return -1; } -Py::Object PythonExtensionBase::getattro( const Py::String & ) +Py::Object PythonExtensionBase::getattro( const Py::String &name ) { - missing_method( getattro ); - return Py::None(); + return asObject( PyObject_GenericGetAttr( selfPtr(), name.ptr() ) ); } -int PythonExtensionBase::setattro( const Py::String &, const Py::Object & ) +int PythonExtensionBase::setattro( const Py::String &name, const Py::Object &value ) { - missing_method( setattro ); - return -1; + return PyObject_GenericSetAttr( selfPtr(), name.ptr(), value.ptr() ); } @@ -1378,7 +1474,18 @@ Py::Object PythonExtensionBase::number_power( const Py::Object &, const Py::Obje // Buffer -// QQQ +int PythonExtensionBase::buffer_get( Py_buffer *buf, int flags ) +{ + missing_method( buffer_get ); + return -1; +} + +int PythonExtensionBase::buffer_release( Py_buffer *buf ) +{ + /* This method is optional and only required if the buffer's + memory is dynamic. */ + return 0; +} //-------------------------------------------------------------------------------- // @@ -1395,13 +1502,13 @@ extern "C" PyObject *method_noargs_call_handler( PyObject *_self_and_name_tuple, Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); if( self_as_void == NULL ) return NULL; ExtensionModuleBase *self = static_cast( self_as_void ); - Object result( self->invoke_method_noargs( PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ) ); + Object result( self->invoke_method_noargs( PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ) ) ); return new_reference_to( result.ptr() ); } @@ -1418,7 +1525,7 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); if( self_as_void == NULL ) return NULL; @@ -1428,7 +1535,7 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_varargs ( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), args ) ); @@ -1448,7 +1555,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); if( self_as_void == NULL ) return NULL; @@ -1464,7 +1571,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), args, keywords ) @@ -1480,7 +1587,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), args, keywords ) diff --git a/CXX/Version.hxx b/CXX/Version.hxx index 398889c90148..ff78b1622f1d 100644 --- a/CXX/Version.hxx +++ b/CXX/Version.hxx @@ -39,8 +39,8 @@ #define __PyCXX_version_hxx__ #define PYCXX_VERSION_MAJOR 6 -#define PYCXX_VERSION_MINOR 1 -#define PYCXX_VERSION_PATCH 1 +#define PYCXX_VERSION_MINOR 2 +#define PYCXX_VERSION_PATCH 4 #define PYCXX_MAKEVERSION( major, minor, patch ) ((major<<16)|(minor<<8)|(patch)) #define PYCXX_VERSION PYCXX_MAKEVERSION( PYCXX_VERSION_MAJOR, PYCXX_VERSION_MINOR, PYCXX_VERSION_PATCH ) #endif diff --git a/CXX/WrapPython.h b/CXX/WrapPython.h index f62d5b4aca4c..118a8740f8ad 100644 --- a/CXX/WrapPython.h +++ b/CXX/WrapPython.h @@ -38,12 +38,23 @@ #ifndef __PyCXX_wrap_python_hxx__ #define __PyCXX_wrap_python_hxx__ -/* Python API mandates Python.h is included *first* */ -#include "Python.h" - // On some platforms we have to include time.h to get select defined #if !defined(__WIN32__) && !defined(WIN32) && !defined(_WIN32) && !defined(_WIN64) #include #endif +// Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h +#if defined(__sun) || defined(sun) +#if defined(_XPG4) +#undef _XPG4 +#endif +#endif + +// Python.h will redefine these and generate warning in the process +#undef _XOPEN_SOURCE +#undef _POSIX_C_SOURCE + +// pull in python definitions +#include + #endif From 2a132861edf0704cc00ec46731e1dccf1134b81c Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Sep 2011 10:40:11 -0400 Subject: [PATCH 176/214] Backport all of the CObject -> PyCapsule changes to Python 2.7 from the Python 3.x side. --- CXX/Python2/ExtensionModule.hxx | 12 ++++++++-- CXX/Python2/ExtensionOldType.hxx | 31 ++++++++++++++++++------- CXX/Python2/IndirectPythonInterface.cxx | 10 ++++++++ CXX/Python2/IndirectPythonInterface.hxx | 2 ++ CXX/Python2/cxx_extensions.cxx | 30 ++++++++++++++++++++---- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/CXX/Python2/ExtensionModule.hxx b/CXX/Python2/ExtensionModule.hxx index 95413801f020..dde3ec6f854b 100644 --- a/CXX/Python2/ExtensionModule.hxx +++ b/CXX/Python2/ExtensionModule.hxx @@ -136,11 +136,19 @@ namespace Py { MethodDefExt *method_def = (*i).second; - static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); + #if PY_VERSION_HEX < 0x02070000 + static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); + #else + static PyObject *self = PyCapsule_New( this, NULL, NULL ); + #endif Tuple args( 2 ); args[0] = Object( self ); - args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) ); + #if PY_VERSION_HEX < 0x02070000 + args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) ); + #else + args[1] = Object( PyCapsule_New( method_def, NULL, NULL ) ); + #endif PyObject *func = PyCFunction_New ( diff --git a/CXX/Python2/ExtensionOldType.hxx b/CXX/Python2/ExtensionOldType.hxx index cfd2fbe6a578..9702b00e7455 100644 --- a/CXX/Python2/ExtensionOldType.hxx +++ b/CXX/Python2/ExtensionOldType.hxx @@ -178,8 +178,11 @@ namespace Py Tuple self( 2 ); self[0] = Object( this ); - self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); - + #if PY_VERSION_HEX < 0x02070000 + self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); + #else + self[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); + #endif PyObject *func = PyCFunction_New( &method_def->ext_meth_def, self.ptr() ); return Object(func, true); @@ -235,8 +238,12 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - MethodDefExt *meth_def = reinterpret_cast *>( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + #if PY_VERSION_HEX < 0x02070000 + void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); + #else + void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); + #endif + MethodDefExt *meth_def = reinterpret_cast *>( capsule ); Object result; // Adding try & catch in case of STL debug-mode exceptions. @@ -271,8 +278,12 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - MethodDefExt *meth_def = reinterpret_cast *>( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + #if PY_VERSION_HEX < 0x02070000 + void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); + #else + void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); + #endif + MethodDefExt *meth_def = reinterpret_cast *>( capsule ); Tuple args( _args ); Object result; @@ -308,8 +319,12 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - MethodDefExt *meth_def = reinterpret_cast *>( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); + #if PY_VERSION_HEX < 0x02070000 + void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); + #else + void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); + #endif + MethodDefExt *meth_def = reinterpret_cast *>( capsule ); Tuple args( _args ); diff --git a/CXX/Python2/IndirectPythonInterface.cxx b/CXX/Python2/IndirectPythonInterface.cxx index d36d1b52612d..203f3f9170ff 100644 --- a/CXX/Python2/IndirectPythonInterface.cxx +++ b/CXX/Python2/IndirectPythonInterface.cxx @@ -42,7 +42,9 @@ namespace Py bool _Buffer_Check( PyObject *op ) { return (op)->ob_type == _Buffer_Type(); } bool _CFunction_Check( PyObject *op ) { return (op)->ob_type == _CFunction_Type(); } bool _Class_Check( PyObject *op ) { return (op)->ob_type == _Class_Type(); } +#if PY_VERSION_HEX < 0x02070000 bool _CObject_Check( PyObject *op ) { return (op)->ob_type == _CObject_Type(); } +#endif bool _Complex_Check( PyObject *op ) { return (op)->ob_type == _Complex_Type(); } bool _Dict_Check( PyObject *op ) { return (op)->ob_type == _Dict_Type(); } bool _File_Check( PyObject *op ) { return (op)->ob_type == _File_Type(); } @@ -123,7 +125,9 @@ static PyObject *ptr__PyTrue = NULL; static PyTypeObject *ptr__Buffer_Type = NULL; static PyTypeObject *ptr__CFunction_Type = NULL; static PyTypeObject *ptr__Class_Type = NULL; +#if PY_VERSION_HEX < 0x02070000 static PyTypeObject *ptr__CObject_Type = NULL; +#endif static PyTypeObject *ptr__Complex_Type = NULL; static PyTypeObject *ptr__Dict_Type = NULL; static PyTypeObject *ptr__File_Type = NULL; @@ -310,7 +314,9 @@ bool InitialisePythonIndirectInterface() ptr__Buffer_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBuffer_Type" ); ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); ptr__Class_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyClass_Type" ); +#if PY_VERSION_HEX < 0x02070000 ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); +#endif ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); ptr__File_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFile_Type" ); @@ -398,7 +404,9 @@ PyObject * _True() { return ptr__PyTrue; } PyTypeObject * _Buffer_Type() { return ptr__Buffer_Type; } PyTypeObject * _CFunction_Type(){ return ptr__CFunction_Type; } PyTypeObject * _Class_Type() { return ptr__Class_Type; } +#if PY_VERSION_HEX < 0x02070000 PyTypeObject * _CObject_Type() { return ptr__CObject_Type; } +#endif PyTypeObject * _Complex_Type() { return ptr__Complex_Type; } PyTypeObject * _Dict_Type() { return ptr__Dict_Type; } PyTypeObject * _File_Type() { return ptr__File_Type; } @@ -542,7 +550,9 @@ PyObject * _True() { return Py_True; } PyTypeObject * _Buffer_Type() { return &PyBuffer_Type; } PyTypeObject * _CFunction_Type() { return &PyCFunction_Type; } PyTypeObject * _Class_Type() { return &PyClass_Type; } +#if PY_VERSION_HEX < 0x02070000 PyTypeObject * _CObject_Type() { return &PyCObject_Type; } +#endif PyTypeObject * _Complex_Type() { return &PyComplex_Type; } PyTypeObject * _Dict_Type() { return &PyDict_Type; } PyTypeObject * _File_Type() { return &PyFile_Type; } diff --git a/CXX/Python2/IndirectPythonInterface.hxx b/CXX/Python2/IndirectPythonInterface.hxx index a29a394c6c6a..33d4b83f34fc 100644 --- a/CXX/Python2/IndirectPythonInterface.hxx +++ b/CXX/Python2/IndirectPythonInterface.hxx @@ -113,8 +113,10 @@ bool _Instance_Check( PyObject *op ); PyTypeObject * _Method_Type(); bool _Method_Check( PyObject *op ); +#if PY_VERSION_HEX < 0x02070000 PyTypeObject * _CObject_Type(); bool _CObject_Check( PyObject *op ); +#endif PyTypeObject * _Complex_Type(); bool _Complex_Check( PyObject *op ); diff --git a/CXX/Python2/cxx_extensions.cxx b/CXX/Python2/cxx_extensions.cxx index 0e0ade093e27..6ae62c7cfb05 100644 --- a/CXX/Python2/cxx_extensions.cxx +++ b/CXX/Python2/cxx_extensions.cxx @@ -1719,7 +1719,11 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + #if PY_VERSION_HEX < 0x02070000 + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + #else + void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); + #endif if( self_as_void == NULL ) return NULL; @@ -1735,7 +1739,11 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + #if PY_VERSION_HEX < 0x02070000 + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + #else + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), + #endif args, keywords ) @@ -1751,7 +1759,11 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + #if PY_VERSION_HEX < 0x02070000 + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + #else + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), + #endif args, keywords ) @@ -1773,7 +1785,11 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + #if PY_VERSION_HEX < 0x02070000 + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); + #else + void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); + #endif if( self_as_void == NULL ) return NULL; @@ -1784,7 +1800,11 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_varargs ( - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + #if PY_VERSION_HEX < 0x02070000 + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), + #else + PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), + #endif args ) ); From 519322ff68f5bc3caacfb884a35a9895cd4d38df Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Sep 2011 11:01:09 -0400 Subject: [PATCH 177/214] Pass Unicode strings to matplotlib, since some of them are > 128. --- examples/pylab_examples/font_table_ttf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 examples/pylab_examples/font_table_ttf.py diff --git a/examples/pylab_examples/font_table_ttf.py b/examples/pylab_examples/font_table_ttf.py old mode 100644 new mode 100755 index 6400efb0bb3d..0a80c535dce4 --- a/examples/pylab_examples/font_table_ttf.py +++ b/examples/pylab_examples/font_table_ttf.py @@ -32,7 +32,7 @@ for ccode, glyphind in codes: if ccode>=256: continue r,c = divmod(ccode,16) - s = chr(ccode) + s = unichr(ccode) chars[r][c] = s From df428f0a2959655a2c8aa43f283ad6f9c2567a63 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Sep 2011 11:01:48 -0400 Subject: [PATCH 178/214] Display a more helpful error message when an 8-bit non-ascii string is passed to matplotlib. --- lib/matplotlib/cbook.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index c3d8ff596394..cd1dc68e197e 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -1820,7 +1820,11 @@ def __call__(self, key): def is_math_text(s): # Did we find an even number of non-escaped dollar signs? # If so, treat is as math text. - s = unicode(s) + try: + s = unicode(s) + except UnicodeDecodeError: + raise ValueError( + "matplotlib display text must have all code points < 128 or use Unicode strings") dollar_count = s.count(r'$') - s.count(r'\$') even_dollars = (dollar_count > 0 and dollar_count % 2 == 0) From dfc1f5a9e60a75768a607c8c8388e3f1be2baf4a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Sep 2011 11:21:54 -0400 Subject: [PATCH 179/214] Fix test_font_styles text so it doesn't use any fonts outside of what is shipped with matplotlib. Addresses #488. --- .../baseline_images/test_text/font_styles.pdf | Bin 22612 -> 16914 bytes .../baseline_images/test_text/font_styles.png | Bin 16766 -> 15874 bytes .../baseline_images/test_text/font_styles.svg | 1023 ++++++++++++++--- lib/matplotlib/tests/test_text.py | 76 +- 4 files changed, 892 insertions(+), 207 deletions(-) diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_styles.pdf b/lib/matplotlib/tests/baseline_images/test_text/font_styles.pdf index ca51cb2ebff9d5bb110ee7d6834bbc805c752a77..5d2f1255fdc6e89df07661fdbb8be4ddd3337434 100644 GIT binary patch delta 5168 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 ZOuq}nX&GW+EEU0V4vT7M=R22A{U5ug-X;J5 delta 9067 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 diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_styles.png b/lib/matplotlib/tests/baseline_images/test_text/font_styles.png index 10ca470ade110d99d4b3c69340264d32eb331955..783a112cb493087fc10041aa64986dabee9d2ab3 100644 GIT binary patch literal 15874 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 Tc~Kq|ABB2M^Jv!Lv)BF~W%90M literal 16766 zcmeHvXHZmIxMizgz<`Qbk_wU(L_|=M5or(_$%uf0ihzPh&L&JCC{d9h5}J%ij_p+e z6|f~sM#(v68fG1*UQNxvH}hxey}4H1YEqxG&)#2H;p_WURps1zmR&3)5@|hI;fxxI zw1S&NTCTHtC4LfYcmFnCn5<8cHCE%F%j&C7@co+G3cA)L66+P>zh$v| zfp%*2RK%u@{({Rn`B&fHYp`)c=gOxWhe&JoTq1v6SZoWr6-eQ}_mSso|ExpD=+_@* zLuD?q)k9KwY5hBly|5P2$NP7EIf*asdahc=M7)YKZ6v<0-FSj{(K$_8hL_9h|NZ6v z+fBH~D??hKw-h*woBUv}Nz_%p_T68g_czX_jpv*D7K}y{dFmZpCWO}AHUTm>nAi? z(wb!~Kfm60*MDzBM1*hD++=@(ZrXKT>0P)=h+>Q5?jP))KZ&ULH#q*?gn!G#zqRt; zhVgILL?!&c+=S?ch|`b#gM;JSOMHSRRF7CRNxF^}ZAY83?wgk6Bau{dH=R)JW0$;r zf+ELA|I^;SbGIoPP(`8`1W z&Ycg}%Y&o)Q)mX`-Sj%HrI~a6#@6g5PT}2p7rN6eTV-$kdVf;;l9h*`R$@<_r?o9$OByOF-g!2N-ypD^TPQdsmY#-(|LA- zm0zB+1z?Z6%HNoOyt|BL!-lDT^TmbPU{T{oUZT0bAMLJ=Rti%0mXeXtA1<6vcAM?o z&b)GEUv7W0`t(q<%q=&@r1n9b_a{Q7?6t06kJ-$|mSNqkB5qc#VBhMR_36_m>A|d9 zjWPH}d$)vzf4k%}A0O@csll3fO(9BNS=o8z*N4xR28jf1Ja?KNO1ev0$`hhr zRVhlfXg*#r-QwJkdFxHQR#JSJjB`BMZ-3a)(!hgNW1XcnR0>y;UY3e_%=rsWPPxg2 zb7sUz$%a#W(~XK)h-LXs^ispkK0jLT8-+*gA1f7+6KP*XB6YvU?)&>+<#`)FnrH&33dRxfmMq_iezr`XLWs8hY4`uIrT zI+?c`gFioJ4WA5Q8N;*h#;rn*S*tV-h1$1>-n(~i|B)lrM{fN5_|U^+XE@zN-iLG0 zRO0H_jqQ@&J7t{G*RZf09vvOsFDUpO&+IhW*O|Fn+{|AA zzC1ZqvJPQ=J2gBdbS={hwGN}DRUEr__uKor3L?-BZ`!n}%U4NQ^xL;@#XF1-i;0yh zOEh0)FA=rw{$bnL#r)#gR-s^zwcB?YdmVFI$liJA@?G4+1sQMAh!D(Ows)Avt-m%Y zMkVxkard~RN-Zm=^bPEP8E?=fquNB>_CU(3L;py6w;v<_Sj$b^E{!g0UCQM=Ad1Iv zTw+W&f6%kYDf;r|%PW8XEm;Soq#9ioXS;`{QjJTRKBnEQKb*DjfK~R8Y&cz-F;QhA zPF4T5mOF*En5$dplGDw1@L>54es9{49#@}ZO%*ME#h9OdQ=6o>8ygrX ztl!5eB69ajadB>^uC8v3^Yl=$6+5MIy4AfETUfX_*MF*H4fe_I?>D1L9-uT_(vO|i1Fvd~2a9Jd?jv7m<> zQ%C+*zY;Z;&e}^94;kmF>Y34Yx|xbc&eGyM7A!`m57ejel2Na2TXW(2u>~Q+=2F>xVa$fSulP7mcJG|!^wl{KnY;H*+Wxq;Y$rLSbVUg@S z?0%(iY0=r^;lo(`ec0HmS35FpRGeycUn*#ot<$#;HIX`cRBO+kJz*tzizA;|a|b?@ zO7kuGR;L=Dqw&cTnUBlI>t!V)1NK}0dG?Mc&Y-|47|dq_m+XLUtJT+Uz z5u|VTntH%e|2s}L1u5G5T_|Oux(@pmWZ-1_ve56iZJ)wspC)Efo4pt5zS_Ry$8*2( zg~i3i#pAB`?(t&%t*+CdUZP=a10y51X_-jJ?>~OnWlay%tGE5>!p{PPw122)8kcOi zW?~{FD_i(c^tgAVm)AN9N#MphM5)-L?FJ4f6SR^lzrNfjey2l0Gx?HkbFOXG+mjEr zAoZpWlGm(RLmim^cyC4g#f-k4<#C5_@{*nE@72`Rn@2+vFJ_os%(-*zp7B?aLnB|@ zeaGBE`rD>Gu;573s+eF2%P=)HHH`wN$*Rot>(*&#X=&ZFMO?G2TPK|`ZO6pS96Hu9 z{VUZt>{d9P+S7AmdRx?ejab#+UL~p-W}3(%%Eb>?pLYESO{h;Z=`WXPtuA{lmSI*S zc=p`6((Z8qNlBenm+^7|A3uBZhSz0rk}UHo_wV2Tp=*eBd^(FJSCOPAQT|4P!nXhX z&z}*eDUF$SgAEt6Z%0fGHTO>&<%^rw#%d*9G!cJ!VA>4)5=AU#cjn~eT+Fi2k7$<;xX&rDjzki^v>+#?_}q;#CxF}R zJLf%d;M5Pxv5s%Sa_)tBFXof7TE?nHE@i7Cc_t1_$g)YaI7HeF{E9ec-R1C|jg5`b zU^m>NU%cb_4$*fXjY9`-onamf%1YiVa;T%gq$4`WKyYG*$zkfB?B19+#4?maBrDVx zE6#D5widdYFhV<;_h;GTxn{(Ft3i zg4*kZI+)=wYUDaqZ_Gp$MyTSO1$aDP&wOqzjqb8cdt=2+) z>#nj2)JAcAy=XC8N)`U}12LQ-$owt+0#eq8P>I^SAb_Sq8g||3%b8yHwX`rlX z7d_ibz=`s3IYS|>#Gm<&<3Ai!iYl@!4H>OVjBrlZi3=Q3cIWFZSw9E5iJ>hqhMzru zUbBK#`nFa{!JlVBTefV80*n*{3_`UqtN##<2ewivUQZ$&5Q^(w`ou*KkiEi~n~YHk z65h|x{}ugXu{ut@B!8;GybJXWy=rQp-uSppPn#+7Y6XoxT%&C$zHHet=EAl^($Y-} zog(g|{=B@ruMvMaC0;Ku~@&4StFIk^vJJE9?$&hBSY6H6}@KQA@l)7*{{l|~mc+CX=*RSJ%+r#f9 z6}|ouC+RjnC~>PXQ&}@!qXNDCPRraf(#NAe>Yn+K)Siv7LT-9%)9#Wqqw{bB*u}?P z%U9!tWWJi4cuCxImw0*qh_oCp{{?>8cHj5aE1d!3^T5F+-W*b^{z`7I_uhT0;V{=r zo$L%U+}1FZkWwgUXBa8}yb{s;tjP_hja(hvIW1;d$%7Jj{#HZ!=zI>qGJVFONYsAl z(y8qv693laN=~G^JjgetojZ4WWWE8y@ThQbMI1Kd*{7fm+Q`pGM@Pp2U(9vOEjfnC zYuP+lxxUgQ+%@Lat5?39kg&7AS}`+8`gn=*$}nl0?plkVIN&GS{m~(M>F$eZhB>10 zVkSST?=!C@N)+QatGnuOOF;(UJBOUxC8Cd-hyO1=Qc+RSS4H&+K6+9=tI|KDJ(yl8vTa|FIpnBptCbDP@<>$M^)zA_QNxJVZ-@9J+DuTusw9IYy zmP)@?x=m*6>%O`9)}>@QMlZ!85AE8+!$W|N?;H@1eac=YrjSO@$KmdaIbn`nJBccn zJDAy+eyi~)w&T3EzHLC5>y$2~5qVTF*OxE{5!V0Z%LuupS$e!`#C-z&WLUNu032)D z*rfA(vtlP|GN{eVmoJ}rdHM4M9Mqc%@#aD@#IEMfZhOutbCJL#22Q=aS&69Vb6syN zCw>|G^kz0%j5l_BiWL6z7f^2+oSAVbeA|d!piyc} zOyA3MoE2HEZV7-jWM5E_X!GP8d7{WSq?<;Xrxett(ZRT*z+7XY8(ZimUCgkV8M#t0 z_FZU~tV=eJ003)qo_(E?NI?{_JBiDn3iEoC?yqf;8qSX_^4vZj08*$0jLtk%m1l2B z`v5kVfIH2hUu#lTLXCV%cSPds`W|z+jU*_YKd(_9EY3@2<5SU~xiOkXUh;8sp8&C` zD;1#)Y(K$XGWyU*8lB+4dvrTHg1Z!A($weRUT;8Y+h?HkP zEX%iyM}%j~)Rsi7#vI6xxi;fwy&9U#h!726lI5l$upuD}%wERg5BwI;$$m>D3UqX8 zqMW8aYC6jSRzM;vBr}-8n46p_6e|N8LN^+0Wr%Yk;vBeMI%@kslkp~zDnEQ#xJo#^Gun4*j83*+XYY&=GB z=x}VPMjM%&Y4-{D<2$AAJeVZ z_Cm0@c_0A;Z?N-CUx+xx3>MV)Luyz9#EZS8!g;vB{yU##=#UQcnsw`{so`$%jTU*z zM0EJ=S5612U|^Msh#DZx1#idP_H7y{4$}hS;+ohVO$UeUi--Yd{xR)^|CDDFGN1#G3~94o||g4{7XY~!C#fk zUV(A!JqgB9m3d1Kxm=>&CFuR?p@-6s1^`Fh}{n1YKrfzc zFZ8jOT!7;6gY3>X-{D8`4-B+xIC|m2h1$=Ld0Z!Jw22niGzf8}-BZTv1p* zcSc|HSWfGLae1rB$$JXEFl?hl3TIA1EUZBNJ@ixj@_)<%bdJw%;o?d`A?jy!pE(`T zZ!k7}Ff_X}0g+8@K6l*8yt;(TJrQS&ZY2OE9F3DuYPW(!)GY#D_}sC!<|X4a)j&JM zfu0EXg>x}$&dq=;Y{$$L;xJT9ms?5%3HesQQ1soqZ(lRL$%-ASk`h|BhxbZ30>c8A(aGlrUSs;au6;@$2i^rygi z7g_6`pL^(q=yc);W4UXFcvg=e^KsO$F&8ZmVviv)y8#`xojY|e(*guF4;#A8MpGG3 z{rXJBTxM>oBW`G}tJdvk8yc^pEl#F~UsF&}c-ggzls$91P|M}gvXgPXOCnvrfB$y+ z?Xmr;*I&AO?faH2sQJm(!_5-KJwRYpC`WCzhEBcFh_hNBxy9I~rc2<-mPjpV z^X5Mi=Sr-kvphRfloS+Hb#z|kxk4l8ha`PF>+|Q&HQ83i1jhz6QU(72q1NchrxY$9 zOL1qEiqZ26xg6S-kt_WuvT+w8<#TMI7so?H4?Ljz4ts8jdk``MF+tE*ld%0)$%{Rw zx9r*#FQ^$$ARLQX0uj0|&9@T3n}|AqfXoujxp>lTyYoBX z)M?Wt!O-cd6hk?`(9ppl2^=2Xu%7SytF~I@FzNcV;V80SQ!X^s+)i*JtI}47_VsjG zEXB58-kZHQt{+0w%dWsBvj^>xU4SBE)vXXtEt)m8^)=f>k6JX{z(a7^|d_?7y(ELc22VO)5i&l{KgXBF3x;vM6E zG1237JO6N+RJ=PImg~OI&Sjy$m~a4WT+gzg=IZt9P`Z0tX|(P%LPySPg{s&Q*NEQp zvWtn7ovlC6ZQi|H`-G}lNIpqMTKW>950;nLz=de0g;0WzknwmGcbBd34+x0<{rPd; z{KQbR9z+xStZ}(JTD~TsXHS~%^AZINi_&XBRhv#3_pOGQCNo*B?lvF#tx2VDv(=c6 zN=7UL8s`NyHQ#Lqblw`eGc;GRauOaAG(wp{B>!3&3$P%<`Jv?|CLUP7>&VxGw9(?- zlMUu6j^2jQ`DpYE?l%&aQ_gdmi{ksbmQpgl&aVpxzsX7lAl`M{CN>Yn#{BHrvjXsu zD&uG+pkp`we0e%ly1#4 zrUQfboPKlzR@KFPhtzJSd=QW@<1X4D+1L5a1#}ejh32t*wh_ooPTOL--OnWOaLBs+ zO4G0AyBun^EZ4^9AKOK?zWd%ekhv#&tIm0D7m>Xs2TSI!F3aeW8$y4U4p%l17a`wr~Mj%P-Ot&Yd~q&@y@fGy%P*%+>5di(&0}c(xR?wBi(i?AXoj z&>P)yrU8rg%Y&C>I4YkeY@i-DIH`S@#Wx_Jv+(jEREa<^!8V<-t0pE1P{%LQ+zO)D zmUV?W4_$C^$p=1$Oq$^|X-0De=1)TIZgFT@2)BilKfl30zr7<4Q#%pkQUQJ`b4@T5 zhj#y>1TH!IcTCG9>*r;DYQN^BZqx>bZsSdiUo)J{KIR{^Jk z5Hkv9{&>zoIN&8ivfCwPm*^rJ9;N;`G@skIJEuEL{p!^yZ^&IpK4BdTsEG(})Gc$QcGwiUC4oR7s@tGn^+C61=FH=_JR#@E$w%*vc+BZ*^G8gP zLaD1WbWg$s`e9!R+q9UB85Id7XP*KkIPNqN%VXN{^<_Mq$y29JO<-~65S%R<3Da=B z+w45#@L;ftra|<(yd`0k4VU>+-jKnD;E`hWgrB1;1giNXb@L^XkKd&-islT2dd~@_ z1F*2dT*k=sLI_F2rqf_o6Vl(l?=VJ}YOj@>>xm4@1@hSL5P}>DzI&Hs@BHP-rnA9~ z`u5G8jty$K0o4s60rQl7XMi^9n=UAoA;FblknShICE~?yI(xP??ha$JF0Yf1=GOr^ zb<&H90!?K|6Q%f6cRtWPT^169O~ky{4$(j9jFn7GGp-1ZEce z7iO%og!k?H3^Q{3FA8+a2xDf_rF`M8@eFI;w^1uLax*NIAGJ${g=4vd1`biD5^_u= z&<%N?yw}LUd|yIJA5gM3bQTjs*celTjpjtn=F{cCYylvGMV?=Zg3HK1tBCN(8(|$;70G{#jmR}lyp;0+JE?V<#(eMuJwa+Vz64z$itv{(ZZJMC8?T*`Ol8a{J$S_Eh;YnU(Z@5QW=melUxd?A;y?|CCpbmHyw-P*=z&*ZEXqIdzAjdlrj$SpOfcUKj4JfaFNfAah$d!c51hM7D+(a+0 z^rtj!stN})GxKb~IeGcOk2lcO1bX+Nj<+6LzFILFeJVFg3NSI&qB)mwG~ zyCLl_qU#f;F_{=tL9wx^(bS&J2nB1+v}o?j%!7kZxQhMlK5|;9cMy6ef@lk8F=XR! z^G7S4xC0RQkSO7otYO>#b;mwP6yU}Q;QvLTgxutbR`hL0`{K~}thDyJ??EENrc#b$ zS7k;%t~l;6^0w8A({1Jop%PQ1N6);R=LGUMaQMwksRw(btminM{5$0|VkMukN4y&t zK7lF=A%W1&^JIXf2{T2Kir5Muq=v|IK7#0Ez(}`yl;C46WN7j#gwU+*K1-fHO3z3Y|

L}b#6-6M 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 aRYzyzbFcDv_X1y%$Y)i~B%iu`|9=3eg1l`2 diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg b/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg index 676f8d230562..dac926de1d15 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg @@ -1,177 +1,854 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index bba84e6b619a..6d8294fa7310 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -6,56 +6,64 @@ @image_comparison(baseline_images=['font_styles']) def test_font_styles(): - from matplotlib.font_manager import FontProperties + from matplotlib import _get_data_path + data_path = _get_data_path() + + def find_matplotlib_font(**kw): + prop = FontProperties(**kw) + path = findfont(prop, directory=data_path) + return FontProperties(fname=path) + + from matplotlib.font_manager import FontProperties, findfont warnings.filterwarnings('ignore','findfont: Font family \[\'Foo\'\] not found. Falling back to .',UserWarning,module='matplotlib.font_manager') fig = plt.figure() ax = plt.subplot( 1, 1, 1 ) - normalFont = FontProperties( family = "sans-serif", - style = "normal", - variant = "normal", - size = 14, - ) + normalFont = find_matplotlib_font( family = "sans-serif", + style = "normal", + variant = "normal", + size = 14, + ) ax.annotate( "Normal Font", (0.1, 0.1), xycoords='axes fraction', fontproperties = normalFont ) - boldFont = FontProperties( family = "Foo", - style = "normal", - variant = "normal", - weight = "bold", - stretch = 500, - size = 14, - ) + boldFont = find_matplotlib_font( family = "Foo", + style = "normal", + variant = "normal", + weight = "bold", + stretch = 500, + size = 14, + ) ax.annotate( "Bold Font", (0.1, 0.2), xycoords='axes fraction', fontproperties = boldFont ) - boldItemFont = FontProperties( family = "sans serif", - style = "italic", - variant = "normal", - weight = 750, - stretch = 500, - size = 14, - ) + boldItemFont = find_matplotlib_font( family = "sans serif", + style = "italic", + variant = "normal", + weight = 750, + stretch = 500, + size = 14, + ) ax.annotate( "Bold Italic Font", (0.1, 0.3), xycoords='axes fraction', fontproperties = boldItemFont ) - lightFont = FontProperties( family = "sans-serif", - style = "normal", - variant = "normal", - weight = 200, - stretch = 500, - size = 14, - ) + lightFont = find_matplotlib_font( family = "sans-serif", + style = "normal", + variant = "normal", + weight = 200, + stretch = 500, + size = 14, + ) ax.annotate( "Light Font", (0.1, 0.4), xycoords='axes fraction', fontproperties = lightFont ) - condensedFont = FontProperties( family = "sans-serif", - style = "normal", - variant = "normal", - weight = 500, - stretch = 100, - size = 14, - ) + condensedFont = find_matplotlib_font( family = "sans-serif", + style = "normal", + variant = "normal", + weight = 500, + stretch = 100, + size = 14, + ) ax.annotate( "Condensed Font", (0.1, 0.5), xycoords='axes fraction', fontproperties = condensedFont ) From 65b773d491685d4db2f0dbb5678c28c19a656740 Mon Sep 17 00:00:00 2001 From: Jae-Joon Lee Date: Sat, 17 Sep 2011 22:24:41 +0900 Subject: [PATCH 180/214] fix GridSpec.update to update axes position only for axes assocaited with the gridspec --- lib/matplotlib/gridspec.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 9367cb485bde..f6f8ceb84846 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -233,14 +233,17 @@ def update(self, **kwargs): if not isinstance(ax, SubplotBase): # Check if sharing a subplots axis if ax._sharex is not None and isinstance(ax._sharex, SubplotBase): - ax._sharex.update_params() - ax.set_position(ax._sharex.figbox) + if ax._sharex.get_subplotspec().get_gridspec() == self: + ax._sharex.update_params() + ax.set_position(ax._sharex.figbox) elif ax._sharey is not None and isinstance(ax._sharey,SubplotBase): - ax._sharey.update_params() - ax.set_position(ax._sharey.figbox) + if ax._sharey.get_subplotspec().get_gridspec() == self: + ax._sharey.update_params() + ax.set_position(ax._sharey.figbox) else: - ax.update_params() - ax.set_position(ax.figbox) + if ax.get_subplotspec().get_gridspec() == self: + ax.update_params() + ax.set_position(ax.figbox) @@ -287,7 +290,7 @@ def tight_layout(self, fig, renderer=None, pad=1.2, h_pad=None, w_pad=None, rect subplot_list = [] num1num2_list = [] subplot_dict = {} - + for ax in fig.axes: locator = ax.get_axes_locator() if hasattr(locator, "get_subplotspec"): @@ -340,7 +343,7 @@ def tight_layout(self, fig, renderer=None, pad=1.2, h_pad=None, w_pad=None, rect pad=pad, h_pad=h_pad, w_pad=w_pad, rect=(left, bottom, right, top)) - + self.update(**kwargs) From 85a26dca55c788c97bbf312b0732db222df55530 Mon Sep 17 00:00:00 2001 From: Damon McDougall Date: Wed, 28 Sep 2011 10:52:51 -0400 Subject: [PATCH 181/214] Added Carey Rappaport's CMRmap This colour map is great for colour images but is also ideal for rendering these images in black and white. Suitable for publications. --- lib/matplotlib/_cm.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index fc92aef278f9..49afb24208e1 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -1736,6 +1736,36 @@ def gfunc32(x): (1.0, 0.150232812, 0.150232812)] } +# Implementation of Carey Rappaport's CMRmap. +# See `A Color Map for Effective Black-and-White Rendering of Color-Scale Images' by Carey Rappaport +# http://www.mathworks.com/matlabcentral/fileexchange/2662-cmrmap-m +_CMRmap_data = {'red' : ( (0.000, 0.00, 0.00), + (0.125, 0.15, 0.15), + (0.250, 0.30, 0.30), + (0.375, 0.60, 0.60), + (0.500, 1.00, 1.00), + (0.625, 0.90, 0.90), + (0.750, 0.90, 0.90), + (0.875, 0.90, 0.90), + (1.000, 1.00, 1.00) ), + 'green' : ( (0.000, 0.00, 0.00), + (0.125, 0.15, 0.15), + (0.250, 0.15, 0.15), + (0.375, 0.20, 0.20), + (0.500, 0.25, 0.25), + (0.625, 0.50, 0.50), + (0.750, 0.75, 0.75), + (0.875, 0.90, 0.90), + (1.000, 1.00, 1.00) ), + 'blue': ( (0.000, 0.00, 0.00), + (0.125, 0.50, 0.50), + (0.250, 0.75, 0.75), + (0.375, 0.50, 0.50), + (0.500, 0.15, 0.15), + (0.625, 0.00, 0.00), + (0.750, 0.10, 0.10), + (0.875, 0.50, 0.50), + (1.000, 1.00, 1.00) )} datad = { 'afmhot': _afmhot_data, @@ -1744,6 +1774,7 @@ def gfunc32(x): 'binary': _binary_data, 'bwr': _bwr_data, 'brg': _brg_data, + 'CMRmap': _CMRmap_data, 'cool': _cool_data, 'copper': _copper_data, 'cubehelix': _cubehelix_data, From 2b7ce9ed80003015bf258c44611cf30bf32cc9d6 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Thu, 29 Sep 2011 15:05:26 -0500 Subject: [PATCH 182/214] * Remove matplotlib.legend from artist_api.rst since it is document in legend_api * Fix pyplot docstring :module: -> :mod to remove error: Unknown interpreted text role "module". * Fix pyplot tight_layout docstring to get rid of 'Unexpected section title.' error * reformatted docstring in tight_layout.auto_adjust_subplotpars * fix what's new bullet list ends w/o blank line issues * remove plotting.rst and arraydata.rst stub docs * Added environment_variables.rst to FAQ index * removed normed warning on Axes.hist * fix an nxutils.point_inside_poly docstring definition list bug --- doc/api/artist_api.rst | 7 -- doc/faq/index.rst | 2 + doc/matplotlibrc | 1 + doc/users/arraydata.rst | 72 --------------- doc/users/plotting.rst | 155 --------------------------------- doc/users/whats_new.rst | 2 + lib/matplotlib/axes.py | 12 +-- lib/matplotlib/figure.py | 7 +- lib/matplotlib/gridspec.py | 7 +- lib/matplotlib/pyplot.py | 9 +- lib/matplotlib/tight_layout.py | 28 +++--- src/nxutils.c | 2 +- 12 files changed, 38 insertions(+), 266 deletions(-) delete mode 100644 doc/users/arraydata.rst delete mode 100644 doc/users/plotting.rst diff --git a/doc/api/artist_api.rst b/doc/api/artist_api.rst index cb662d6c71ca..2ec41bb5c94f 100644 --- a/doc/api/artist_api.rst +++ b/doc/api/artist_api.rst @@ -15,13 +15,6 @@ artists :undoc-members: :show-inheritance: -:mod:`matplotlib.legend` -============================= - -.. automodule:: matplotlib.legend - :members: - :undoc-members: - :show-inheritance: :mod:`matplotlib.lines` ============================= diff --git a/doc/faq/index.rst b/doc/faq/index.rst index ac1fc7b1b1b7..b41610b05652 100644 --- a/doc/faq/index.rst +++ b/doc/faq/index.rst @@ -18,3 +18,5 @@ The Matplotlib FAQ usage_faq.rst howto_faq.rst troubleshooting_faq.rst + environment_variables_faq.rst + diff --git a/doc/matplotlibrc b/doc/matplotlibrc index aca4828a0799..5c9685987e24 100644 --- a/doc/matplotlibrc +++ b/doc/matplotlibrc @@ -13,3 +13,4 @@ docstring.hardcopy : True # set this when you want to generate hardcopy docstri #examples.download : False # False to bypass downloading mechanism #examples.directory : /your/path/to/sample_data/ # directory to look in if download is false + diff --git a/doc/users/arraydata.rst b/doc/users/arraydata.rst deleted file mode 100644 index 9db3c505eace..000000000000 --- a/doc/users/arraydata.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. _arraydata: - -*********************************************** -Plotting 2-D arrays or functions of 2 variables -*********************************************** - -In this chapter we will address methods for plotting a -scalar function of two variables. Here are some examples: - -* A photographic image, represented as a 2-D array of - colors; the grid is regular, with each element of the - array corresponding to a square pixel. - -* Earth surface elevation and ocean bottom topography, - represented as a 2-D array of heights; the grid is - rectangular in latitude and longitude, but the latitude - increment may not be uniform--often it will decrease - toward the poles. - -* A mathematical function of two variables, such as a - bivariate Gaussian probability density. - -Note: in this chapter we will assume the data to be plotted -are on a grid. If you have scalar data of two -variables, but the data are not on a grid - for -example, sea level at island stations - then you will need -to use an interpolation or other gridding routine -before you can use any of the -plotting methods we will discuss here. - -As a 2-D plotting library, matplotlib offers two basic -styles of plot for scalar functions of two variables: an -image style and a contour style. The image style renders -the data as either a continuously-varying field of color or -a set of contiguous colored quadrilaterals. Hence, the -image style is a direct representation of the data array. -The contour style is less direct; isolines of the data are -calculated and then either plotted as lines or used to delimit -colored regions. - -.. _image_styles: - -Image (or pcolor) styles -======================== - -some text - -.. _image: - -image ------ - -image text and example - -.. _pcolor: - -pcolor ------- - -pcolor and pcolorfast, including quadmesh variant - -.. _contour: - -Contouring -========== - -contour and contourf - - - - - diff --git a/doc/users/plotting.rst b/doc/users/plotting.rst deleted file mode 100644 index 18f0b0e2fd83..000000000000 --- a/doc/users/plotting.rst +++ /dev/null @@ -1,155 +0,0 @@ -.. _plotting-guide: - -*************** -Plotting guide -*************** - -An in-depth, tutorial style guide to the matplotlib plotting -functions, which explains the most important keyword arguments with -examples and figures. - -.. _image-plots: - -Images -====== -:func:`~matplotlib.pyplot.imshow` - -TODO; see :ref:`how-to-contribute-docs`. - - -.. _colormaps-plots: - -Colormaps -========== - - -TODO; see :ref:`how-to-contribute-docs`. - -.. _colorbars-plots: - -Colorbars -========== - -:func:`~matplotlib.pyplot.colorbar` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _contour-plots: - -Contouring -========== - -:func:`~matplotlib.pyplot.contour` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _scatter-plots: - -Scatter plots -============== - -:func:`~matplotlib.pyplot.scatter` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _log-plots: - -Log plots -============== - -:func:`~matplotlib.pyplot.semilogx`, :func:`~matplotlib.pyplot.semilogy` and :func:`~matplotlib.pyplot.loglog` - -.. _polar-plots: - -Polar plots -============== - -:func:`~matplotlib.pyplot.polar` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _filled-plots: - -Filled plots -============== - -:func:`~matplotlib.pyplot.fill` and :mod:`~matplotlib.patches` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _bar-plots: - -Bar charts, histograms and errorbars -====================================== - -:func:`~matplotlib.pyplot.bar`, :func:`~matplotlib.pyplot.barh`, -:func:`~matplotlib.pyplot.errorbar` and -:func:`~matplotlib.pyplot.hist` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _time-series-plots: - -Timeseries plots -========================== - -:func:`~matplotlib.pyplot.acorr`, :func:`~matplotlib.pyplot.xcorr`, :func:`~matplotlib.pyplot.psd`, :func:`~matplotlib.pyplot.csd`, -:func:`~matplotlib.pyplot.cohere`, :func:`~matplotlib.pyplot.specgram` -and the windowing and detrending functions in :mod:`matplotlib.mlab`. - -TODO; see :ref:`how-to-contribute-docs`. - -.. _sparsity-plots: - -Sparsity plots -========================== - -:func:`~matplotlib.pyplot.spy` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _boxplots-plots: - -Boxplots -========================== - -:func:`~matplotlib.pyplot.boxplot` - -TODO; see :ref:`how-to-contribute-docs`. - -.. _date-plots: - -Working with dates -========================== - -TODO; see :ref:`how-to-contribute-docs`. - -.. _masked-data-plots: - -Working with masked/missing data -================================== - -TODO; see :ref:`how-to-contribute-docs`. - -.. _collections-plots: - -Working with collections -================================== - -TODO; see :ref:`how-to-contribute-docs`. - -.. _legend-plots: - -Creating figure and axes legends -================================== -:func:`~matplotlib.pyplot.legend` and :func:`~matplotlib.pyplot.figlegend` - -:ref:`plotting-guide-legend` - -Annotating plot -=============== -:func:`~matplotlib.pyplot.text` and :func:`~matplotlib.pyplot.annotate` - -:ref:`plotting-guide-annotation` - - diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 2613d4d1261f..65bdb1f64d6e 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -133,10 +133,12 @@ as 2D plotting, Ben Root has made several improvements to the * Most 3D plotting functions now support empty inputs * Ticker offset display added: + .. plot:: mpl_examples/mplot3d/offset_demo.py * :meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` gains *zdir* and *offset* kwargs. You can now do this: + .. plot:: mpl_examples/mplot3d/contourf3d_demo2.py Numerix support removed diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index ea8657b186e9..db2319383ed7 100644 --- a/lib/matplotlib/axes.py +++ b/lib/matplotlib/axes.py @@ -2067,7 +2067,7 @@ def grid(self, b=None, which='major', axis='both', **kwargs): *axis* can be 'both' (default), 'x', or 'y' to control which set of gridlines are drawn. - *kawrgs* are used to set the grid line properties, eg:: + *kwargs* are used to set the grid line properties, eg:: ax.grid(color='r', linestyle='-', linewidth=2) @@ -7662,16 +7662,6 @@ def hist(x, bins=10, range=None, normed=False, weights=None, db = np.diff(bins) m = (m.astype(float) / db) / m.sum() n.append(m) - if normed and db.std() > 0.01 * db.mean(): - warnings.warn(""" - This release fixes a normalization bug in the NumPy histogram - function prior to version 1.5, occuring with non-uniform - bin widths. The returned and plotted value is now a density: - n / (N * bin width), - where n is the bin count and N the total number of points. - """) - - if cumulative: slc = slice(None) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index de9c1a934cc6..5cef5b222759 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1310,10 +1310,11 @@ def get_tightbbox(self, renderer): def tight_layout(self, renderer=None, pad=1.2, h_pad=None, w_pad=None): - """Adjust subplot parameters to give specified padding. + """ + Adjust subplot parameters to give specified padding. + + Parameters: - Parameters - ---------- pad : float padding between the figure edge and the edges of subplots, as a fraction of the font-size. h_pad, w_pad : float diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 9367cb485bde..8fc3e8cb4fd0 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -268,10 +268,11 @@ def locally_modified_subplot_params(self): def tight_layout(self, fig, renderer=None, pad=1.2, h_pad=None, w_pad=None, rect=None): - """Adjust subplot parameters to give specified padding. + """ + Adjust subplot parameters to give specified padding. - Parameters - ---------- + Parameters: + pad : float padding between the figure edge and the edges of subplots, as a fraction of the font-size. h_pad, w_pad : float diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index f5dd5e1df2cf..e15c640cf765 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -457,7 +457,7 @@ def draw(): A more object-oriented alternative, given any :class:`~matplotlib.figure.Figure` instance, :attr:`fig`, that - was created using a :module:`~matplotlib.pyplot` function, is:: + was created using a :mod:`~matplotlib.pyplot` function, is:: fig.canvas.draw() @@ -1035,10 +1035,11 @@ def subplot_tool(targetfig=None): def tight_layout(pad=1.2, h_pad=None, w_pad=None): - """Adjust subplot parameters to give specified padding. + """ + Adjust subplot parameters to give specified padding. + + Parameters: - Parameters - ---------- pad : float padding between the figure edge and the edges of subplots, as a fraction of the font-size. h_pad, w_pad : float diff --git a/lib/matplotlib/tight_layout.py b/lib/matplotlib/tight_layout.py index 1098e599acd7..52e2236098fa 100644 --- a/lib/matplotlib/tight_layout.py +++ b/lib/matplotlib/tight_layout.py @@ -42,20 +42,28 @@ def auto_adjust_subplotpars(fig, renderer, Return a dictionary of subplot parameters so that spacing between subplots are adjusted. Note that this function ignore geometry information of subplot itself, but uses what is given by - nrows_ncols and num1num2_list parameteres. Also, the results could be - incorrect if some subplots have adjustable=datalim. + *nrows_ncols* and *num1num2_list* parameteres. Also, the results could be + incorrect if some subplots have ``adjustable=datalim``. - Parameters - ---------- - nrows_ncols : number of rows and number of columns of the grid. - num1num2_list : list of numbers specifying the area occupied by the subplot - subplot_list : list of subplots that will be used to calcuate optimal subplot_params. + Parameters: + + nrows_ncols + number of rows and number of columns of the grid. + + num1num2_list + list of numbers specifying the area occupied by the subplot + + subplot_list + list of subplots that will be used to calcuate optimal subplot_params. + pad : float - padding between the figure edge and the edges of subplots, as a fraction of the font-size. + padding between the figure edge and the edges of subplots, as a fraction of the font-size. h_pad, w_pad : float - padding (height/width) between edges of adjacent subplots. + padding (height/width) between edges of adjacent subplots. Defaults to `pad_inches`. - rect : [left, bottom, right, top] in normalized (0, 1) figure coordinates. + + rect + [left, bottom, right, top] in normalized (0, 1) figure coordinates. """ diff --git a/src/nxutils.c b/src/nxutils.c index c88bdf40c6df..e7d69793c2e5 100644 --- a/src/nxutils.c +++ b/src/nxutils.c @@ -231,7 +231,7 @@ static PyMethodDef module_methods[] = { "Return a boolean ndarray, True for points inside the polygon.\n\n" "*xypoints*\n a sequence of N x,y pairs.\n" "*xyverts*\n sequence of x,y vertices of the polygon.\n" - "*mask* an ndarray of length N.\n\n" + "*mask*\n an ndarray of length N.\n\n" "A point on the boundary may be treated as inside or outside.\n" "See `pnpoly `_\n"}, {NULL} /* Sentinel */ From aef53adc877650ff852781fb2ad8e2d71220c7f5 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Fri, 30 Sep 2011 08:07:01 -0500 Subject: [PATCH 183/214] added double pendulum examples and linked in whats new --- doc/users/whats_new.rst | 12 +-- .../animation/double_pendulum_animated.py | 87 +++++++++++++++++++ 2 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 examples/animation/double_pendulum_animated.py diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 65bdb1f64d6e..9961dab8a9e0 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -30,12 +30,12 @@ Kevin Davies has extended Yannick Copin's original Sankey example into a module Animation --------- -Ryan May has written a backend-independent -framework for creating animated figures. The :mod:`~matplotlib.animation` -module is intended to replace the -backend-specific examples formerly in the :ref:`examples-index` -listings. Examples using the new framework are in -:ref:`animation-examples-index`. +Ryan May has written a backend-independent framework for creating +animated figures. The :mod:`~matplotlib.animation` module is intended +to replace the backend-specific examples formerly in the +:ref:`examples-index` listings. Examples using the new framework are +in :ref:`animation-examples-index`; see the entrancing :ref:`double +pendulum ` in action. This should be considered as a beta release of the framework; please try it and provide feedback. diff --git a/examples/animation/double_pendulum_animated.py b/examples/animation/double_pendulum_animated.py new file mode 100644 index 000000000000..dac1d669635e --- /dev/null +++ b/examples/animation/double_pendulum_animated.py @@ -0,0 +1,87 @@ +# Double pendulum formula translated from the C code at +# http://www.physics.usyd.edu.au/~wheat/dpend_html/solve_dpend.c + +from numpy import sin, cos, pi, array +import numpy as np +import matplotlib.pyplot as plt +import scipy.integrate as integrate +import matplotlib.animation as animation + +G = 9.8 # acceleration due to gravity, in m/s^2 +L1 = 1.0 # length of pendulum 1 in m +L2 = 1.0 # length of pendulum 2 in m +M1 = 1.0 # mass of pendulum 1 in kg +M2 = 1.0 # mass of pendulum 2 in kg + + +def derivs(state, t): + + dydx = np.zeros_like(state) + dydx[0] = state[1] + + del_ = state[2]-state[0] + den1 = (M1+M2)*L1 - M2*L1*cos(del_)*cos(del_) + dydx[1] = (M2*L1*state[1]*state[1]*sin(del_)*cos(del_) + + M2*G*sin(state[2])*cos(del_) + M2*L2*state[3]*state[3]*sin(del_) + - (M1+M2)*G*sin(state[0]))/den1 + + dydx[2] = state[3] + + den2 = (L2/L1)*den1 + dydx[3] = (-M2*L2*state[3]*state[3]*sin(del_)*cos(del_) + + (M1+M2)*G*sin(state[0])*cos(del_) + - (M1+M2)*L1*state[1]*state[1]*sin(del_) + - (M1+M2)*G*sin(state[2]))/den2 + + return dydx + +# create a time array from 0..100 sampled at 0.1 second steps +dt = 0.05 +t = np.arange(0.0, 20, dt) + +# th1 and th2 are the initial angles (degrees) +# w10 and w20 are the initial angular velocities (degrees per second) +th1 = 120.0 +w1 = 0.0 +th2 = -10.0 +w2 = 0.0 + +rad = pi/180 + +# initial state +state = np.array([th1, w1, th2, w2])*pi/180. + +# integrate your ODE using scipy.integrate. +y = integrate.odeint(derivs, state, t) + +x1 = L1*sin(y[:,0]) +y1 = -L1*cos(y[:,0]) + +x2 = L2*sin(y[:,2]) + x1 +y2 = -L2*cos(y[:,2]) + y1 + +fig = plt.figure() +ax = fig.add_subplot(111, autoscale_on=False, xlim=(-2, 2), ylim=(-2, 2)) +ax.grid() + +line, = ax.plot([], [], 'o-', lw=2) +time_template = 'time = %.1fs' +time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes) + +def init(): + line.set_data([], []) + time_text.set_text('') + return line, time_text + +def animate(i): + thisx = [0, x1[i], x2[i]] + thisy = [0, y1[i], y2[i]] + + line.set_data(thisx, thisy) + time_text.set_text(time_template%(i*dt)) + return line, time_text + +ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), + interval=25, blit=True, init_func=init) + +plt.show() From 1133e83d72a9af865ffdfda7c9ea6560c40afc36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Seppa=CC=88nen?= Date: Sun, 2 Oct 2011 10:25:07 +0300 Subject: [PATCH 184/214] Don't set http request headers with content None Attempts to fix issue #498. I can't reproduce the issue myself, so I don't know if this is the real culprit, but it shouldn't do any harm. --- lib/matplotlib/cbook.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py index cd1dc68e197e..05c24acb3e83 100644 --- a/lib/matplotlib/cbook.py +++ b/lib/matplotlib/cbook.py @@ -552,8 +552,13 @@ def https_request(self, req): url = req.get_full_url() if url in self.cache: _, etag, lastmod = self.cache[url] - req.add_header("If-None-Match", etag) - req.add_header("If-Modified-Since", lastmod) + if etag is not None: + req.add_header("If-None-Match", etag) + if lastmod is not None: + req.add_header("If-Modified-Since", lastmod) + matplotlib.verbose.report( + "ViewVCCachedServer: request headers %s" % req.header_items(), + "debug") return req def https_error_304(self, req, fp, code, msg, hdrs): From 9b86e2134c57f56320fa23df5e8466835031e58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Seppa=CC=88nen?= Date: Sun, 2 Oct 2011 19:06:51 +0300 Subject: [PATCH 185/214] Fix mathtext errors in angle_helper.py Fixes issue #499. --- lib/mpl_toolkits/axisartist/angle_helper.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mpl_toolkits/axisartist/angle_helper.py b/lib/mpl_toolkits/axisartist/angle_helper.py index a07c961f3941..3fc6ce2860e8 100644 --- a/lib/mpl_toolkits/axisartist/angle_helper.py +++ b/lib/mpl_toolkits/axisartist/angle_helper.py @@ -325,9 +325,9 @@ def __call__(self, direction, factor, values): return [r"$%s^{\circ}$" % (str(v),) for v in ss*values] class FormatterHMS(FormatterDMS): - deg_mark = "^{\mathrm h}" - min_mark = "^{\mathrm m}" - sec_mark = "^{\mathrm s}" + deg_mark = "^\mathrm{h}" + min_mark = "^\mathrm{m}" + sec_mark = "^\mathrm{s}" fmt_d = "$%d"+deg_mark+"$" fmt_ds = r"$%d.\!\!"+deg_mark+"%s$" From d0ba36a0850f0bdb364595c9a8ab32db354a5bc8 Mon Sep 17 00:00:00 2001 From: John Hunter Date: Sun, 2 Oct 2011 11:08:30 -0500 Subject: [PATCH 186/214] added double pendulum embedded youtube video to whats_new and documented how to do it in the coding_guide --- doc/devel/documenting_mpl.rst | 31 +++++++++++++++++++ doc/users/whats_new.rst | 7 ++++- .../animation/double_pendulum_animated.py | 1 + lib/matplotlib/animation.py | 4 ++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/doc/devel/documenting_mpl.rst b/doc/devel/documenting_mpl.rst index bf256910cd4f..4bfb21d9506f 100644 --- a/doc/devel/documenting_mpl.rst +++ b/doc/devel/documenting_mpl.rst @@ -251,6 +251,37 @@ insert the following special comment anywhere in the script:: # -*- noplot -*- +Animations +---------- + +We have a matplotlib google/gmail account with username ``mplgithub`` +which we used to setup the github account but can be used for other +purposes, like hosting google docs or youtube videos. You can embed a +matplotlib animation in the docs by first saving the animation as a +movie using :meth:`matplotlib.animation.Animation.save`, and then +uploading to `matplotlib's youtube +channel `_ and inserting the +embedding string youtube provides like:: + + .. raw:: html + + + +An example save command to generate a movie looks like this + +.. sourcecode:: python + + ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), + interval=25, blit=True, init_func=init) + + ani.save('double_pendulum.mp4', fps=15) + +Contact John Hunter for the login password to upload youtube videos of +google docs to the mplgithub account. + .. _referring-to-mpl-docs: Referring to mpl documents diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 9961dab8a9e0..4d293b802086 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -35,7 +35,12 @@ animated figures. The :mod:`~matplotlib.animation` module is intended to replace the backend-specific examples formerly in the :ref:`examples-index` listings. Examples using the new framework are in :ref:`animation-examples-index`; see the entrancing :ref:`double -pendulum ` in action. +pendulum ` which uses +:meth:`matplotlib.animation.Animation.save` to create the movie below. + +.. raw:: html + + This should be considered as a beta release of the framework; please try it and provide feedback. diff --git a/examples/animation/double_pendulum_animated.py b/examples/animation/double_pendulum_animated.py index dac1d669635e..01d2034b68fa 100644 --- a/examples/animation/double_pendulum_animated.py +++ b/examples/animation/double_pendulum_animated.py @@ -84,4 +84,5 @@ def animate(i): ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), interval=25, blit=True, init_func=init) +#ani.save('double_pendulum.mp4', fps=15, clear_temp=False) plt.show() diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 9ff014d26423..9de83226da7b 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -87,6 +87,8 @@ def save(self, filename, fps=5, codec='mpeg4', clear_temp=True, ''' Saves a movie file by drawing every frame. + *filename* is the output filename, eg :file:`mymovie.mp4` + *fps* is the frames per second in the movie *codec* is the codec to be used,if it is supported by the output method. @@ -430,7 +432,7 @@ def __init__(self, fig, func, frames=None ,init_func=None, fargs=None, self._init_func = init_func # Needs to be initialized so the draw functions work without checking - self._save_seq = [] + self._save_seq = [] TimedAnimation.__init__(self, fig, **kwargs) From ba04a30e1b251019c7fb022448de6772fb335e8e Mon Sep 17 00:00:00 2001 From: John Hunter Date: Sun, 2 Oct 2011 14:19:15 -0500 Subject: [PATCH 187/214] added some verbose reporting to animation --- examples/animation/double_pendulum_animated.py | 2 +- lib/matplotlib/animation.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/animation/double_pendulum_animated.py b/examples/animation/double_pendulum_animated.py index 01d2034b68fa..da90eb2cca92 100644 --- a/examples/animation/double_pendulum_animated.py +++ b/examples/animation/double_pendulum_animated.py @@ -84,5 +84,5 @@ def animate(i): ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), interval=25, blit=True, init_func=init) -#ani.save('double_pendulum.mp4', fps=15, clear_temp=False) +#ani.save('double_pendulum.mp4', fps=15, clear_temp=True) plt.show() diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 9de83226da7b..dc868c992a3a 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -21,6 +21,7 @@ # * Need to consider event sources to allow clicking through multiple figures import itertools from matplotlib.cbook import iterable +from matplotlib import verbose class Animation(object): ''' @@ -120,6 +121,7 @@ def save(self, filename, fps=5, codec='mpeg4', clear_temp=True, self._draw_next_frame(data, blit=False) fname = '%s%04d.png' % (frame_prefix, idx) fnames.append(fname) + verbose.report('Animation.save: saved frame %d to fname=%s'%(idx, fname), level='debug') self._fig.savefig(fname) self._make_movie(filename, fps, codec, frame_prefix) @@ -127,6 +129,7 @@ def save(self, filename, fps=5, codec='mpeg4', clear_temp=True, #Delete temporary files if clear_temp: import os + verbose.report('Animation.save: clearing temporary fnames=%s'%str(fnames), level='debug') for fname in fnames: os.remove(fname) @@ -155,7 +158,9 @@ def _make_movie(self, fname, fps, codec, frame_prefix, cmd_gen=None): from subprocess import Popen, PIPE if cmd_gen is None: cmd_gen = self.ffmpeg_cmd - proc = Popen(cmd_gen(fname, fps, codec, frame_prefix), shell=False, + command = cmd_gen(fname, fps, codec, frame_prefix) + verbose.report('Animation._make_movie running command: %s'%' '.join(command)) + proc = Popen(command, shell=False, stdout=PIPE, stderr=PIPE) proc.wait() From 1391ad05bed6ed6217a1a1563858d0ad3c04fd69 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 2 Oct 2011 11:48:39 -1000 Subject: [PATCH 188/214] geo.py: prevent division by zero in Mollweide transform The Newton-Raphson iteration converges more slowly near the poles, and triggers a divide-by-zero at the poles. Although the previous transform was handling this correctly in the sense that it was still giving the right answer, the divide-by-zero warning was non-optimal. The present version switches to a Taylor-series approximation for latitudes within 5 degrees of the poles. This avoids the divide-by-zero, and also runs faster on arrays with a full range of latitudes. --- lib/matplotlib/projections/geo.py | 36 ++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 8a20f5c2768d..182266ca0a62 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -436,23 +436,35 @@ def __init__(self, resolution): def transform(self, ll): def d(theta): delta = -(theta + np.sin(theta) - pi_sin_l) / (1 + np.cos(theta)) - return delta, abs(delta) > 0.001 + return delta, np.abs(delta) > 0.001 - longitude = ll[:, 0:1] - latitude = ll[:, 1:2] + longitude = ll[:, 0] + latitude = ll[:, 1] + + clat = np.pi/2 - np.abs(latitude) + ihigh = clat < 0.087 # within 5 degrees of the poles + ilow = ~ihigh + aux = np.empty(latitude.shape, dtype=np.float) - pi_sin_l = np.pi * np.sin(latitude) - theta = 2.0 * latitude - delta, large_delta = d(theta) - while np.any(large_delta): - theta += np.where(large_delta, delta, 0) + if ilow.any(): # Newton-Raphson iteration + pi_sin_l = np.pi * np.sin(latitude[ilow]) + theta = 2.0 * latitude[ilow] delta, large_delta = d(theta) - aux = theta / 2 + while np.any(large_delta): + theta[large_delta] += delta[large_delta] + delta, large_delta = d(theta) + aux[ilow] = theta / 2 - x = (2.0 * np.sqrt(2.0) * longitude * np.cos(aux)) / np.pi - y = (np.sqrt(2.0) * np.sin(aux)) + if ihigh.any(): # Taylor series-based approx. solution + e = clat[ihigh] + d = 0.5 * (3 * np.pi * e**2) ** (1.0/3) + aux[ihigh] = (np.pi/2 - d) * np.sign(latitude[ihigh]) - return np.concatenate((x, y), 1) + xy = np.empty(ll.shape, dtype=np.float) + xy[:,0] = (2.0 * np.sqrt(2.0) / np.pi) * longitude * np.cos(aux) + xy[:,1] = np.sqrt(2.0) * np.sin(aux) + + return xy transform.__doc__ = Transform.transform.__doc__ transform_non_affine = transform From 533e5fba0bee341bec31bb2987c19e86b05cb631 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sun, 2 Oct 2011 12:55:28 -1000 Subject: [PATCH 189/214] geo.py: fix divide-by-zero warning in Aitoff transform An attempt to do this had been make by masking zero values in the denominator; but at least with current numpy, this is not enough, because the __div__ method of the first argument is used. The solution is to ensure that the first argument is also a masked array. --- lib/matplotlib/projections/geo.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 182266ca0a62..a5d8e3a50a75 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -271,16 +271,16 @@ def transform(self, ll): cos_latitude = np.cos(latitude) alpha = np.arccos(cos_latitude * np.cos(half_long)) - # Mask this array, or we'll get divide-by-zero errors + # Mask this array or we'll get divide-by-zero errors alpha = ma.masked_where(alpha == 0.0, alpha) + # The numerators also need to be masked so that masked + # division will be invoked. # We want unnormalized sinc. numpy.sinc gives us normalized sinc_alpha = ma.sin(alpha) / alpha - x = (cos_latitude * np.sin(half_long)) / sinc_alpha - y = (np.sin(latitude) / sinc_alpha) - x.set_fill_value(0.0) - y.set_fill_value(0.0) - return np.concatenate((x.filled(), y.filled()), 1) + x = (cos_latitude * ma.sin(half_long)) / sinc_alpha + y = (ma.sin(latitude) / sinc_alpha) + return np.concatenate((x.filled(0), y.filled(0)), 1) transform.__doc__ = Transform.transform.__doc__ transform_non_affine = transform From 1e8152830585a722f67b97f12696ba27de85f63a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 4 Oct 2011 13:58:41 -0400 Subject: [PATCH 190/214] Fix the doc build hanging (based on a report by Sandro Tosi). --- doc/make.py | 2 +- lib/matplotlib/sphinxext/plot_directive.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/make.py b/doc/make.py index 243d431dc442..74c7c54b80b0 100755 --- a/doc/make.py +++ b/doc/make.py @@ -138,7 +138,7 @@ def html(): options = "-D plot_formats=\"[('png', 80)]\"" else: options = '' - if os.system('sphinx-build %s -P -b html -d build/doctrees . build/html' % options): + if os.system('sphinx-build %s -b html -d build/doctrees . build/html' % options): raise SystemExit("Building HTML failed.") figures_dest_path = 'build/html/pyplots' diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index 98731295f57a..f9ca13630114 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -498,7 +498,10 @@ def render_figures(code, code_path, output_dir, output_base, context, # -- Parse format list default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 200} formats = [] - for fmt in config.plot_formats: + plot_formats = config.plot_formats + if isinstance(plot_formats, (str, unicode)): + plot_formats = eval(plot_formats) + for fmt in plot_formats: if isinstance(fmt, str): formats.append((fmt, default_dpi.get(fmt, 80))) elif type(fmt) in (tuple, list) and len(fmt)==2: @@ -584,6 +587,9 @@ def render_figures(code, code_path, output_dir, output_base, context, results.append((code_piece, images)) + if not context: + clear_state(config.plot_rcparams) + return results def run(arguments, content, options, state_machine, state, lineno): From ea739190b41039464978f50b2b4b1c5c51e6c4ad Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 4 Oct 2011 14:32:25 -0400 Subject: [PATCH 191/214] Update how a float array is specified for newer versions of Numpy --- lib/matplotlib/lines.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index b57704024265..588a9bcd7300 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -387,26 +387,26 @@ def recache(self, always=False): if always or self._invalidx: xconv = self.convert_xunits(self._xorig) if ma.isMaskedArray(self._xorig): - x = ma.asarray(xconv, float) + x = ma.asarray(xconv, np.float_) else: - x = np.asarray(xconv, float) + x = np.asarray(xconv, np.float_) x = x.ravel() else: x = self._x if always or self._invalidy: yconv = self.convert_yunits(self._yorig) if ma.isMaskedArray(self._yorig): - y = ma.asarray(yconv, float) + y = ma.asarray(yconv, np.float_) else: - y = np.asarray(yconv, float) + y = np.asarray(yconv, np.float_) y = y.ravel() else: y = self._y if len(x)==1 and len(y)>1: - x = x * np.ones(y.shape, float) + x = x * np.ones(y.shape, np.float_) if len(y)==1 and len(x)>1: - y = y * np.ones(x.shape, float) + y = y * np.ones(x.shape, np.float_) if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') @@ -746,7 +746,7 @@ def set_marker(self, marker): %(MarkerAccepts)s """ self._marker.set_marker(marker) - + def set_markeredgecolor(self, ec): """ Set the marker edge color From f6194f84ab9700b16265b0347289f7e248a46559 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 5 Oct 2011 08:19:57 -0400 Subject: [PATCH 192/214] Don't build thumbnails in parallel, as that seems to mysteriously break on some systems. --- doc/sphinxext/gen_gallery.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/doc/sphinxext/gen_gallery.py b/doc/sphinxext/gen_gallery.py index d47df8a7f088..aadc2c0e9b8c 100644 --- a/doc/sphinxext/gen_gallery.py +++ b/doc/sphinxext/gen_gallery.py @@ -105,20 +105,10 @@ def gen_gallery(app, doctree): fh.write(content) fh.close() - try: - import multiprocessing - app.builder.info("generating thumbnails... ", nonl=True) - pool = multiprocessing.Pool() - pool.map(make_thumbnail, thumbnails.iteritems()) - pool.close() - pool.join() - app.builder.info("done") - - except ImportError: - for key in app.builder.status_iterator( - thumbnails.iterkeys(), "generating thumbnails... ", - length=len(thumbnails)): - image.thumbnail(key, thumbnails[key], 0.3) + for key in app.builder.status_iterator( + thumbnails.iterkeys(), "generating thumbnails... ", + length=len(thumbnails)): + image.thumbnail(key, thumbnails[key], 0.3) def setup(app): app.connect('env-updated', gen_gallery) From e315e90532a5d93ba48088537b94cc3822e662ab Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Wed, 5 Oct 2011 14:20:02 -1000 Subject: [PATCH 193/214] qt4agg: fix blit bug; closes #506 A simple Cursor test script was causing infinite recursion. The solution here involves using separate attributes for the replot flag (meaning an Agg draw is needed) and the blitbox. This clarifies the logic and removes the need to override the inherited copy_from_bbox method. --- lib/matplotlib/backends/backend_qt4agg.py | 32 +++++++---------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4agg.py b/lib/matplotlib/backends/backend_qt4agg.py index 26f96dd6f012..f6f4d56c94b8 100644 --- a/lib/matplotlib/backends/backend_qt4agg.py +++ b/lib/matplotlib/backends/backend_qt4agg.py @@ -58,6 +58,7 @@ def __init__( self, figure ): FigureCanvasAgg.__init__( self, figure ) self.drawRect = False self.rect = [] + self.blitbox = None self.replot = True self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent) @@ -77,11 +78,11 @@ def paintEvent( self, e ): if DEBUG: print 'FigureCanvasQtAgg.paintEvent: ', self, \ self.get_width_height() - # only replot data when needed - if type(self.replot) is bool: # might be a bbox for blitting - if self.replot: - FigureCanvasAgg.draw(self) + if self.replot: + FigureCanvasAgg.draw(self) + self.replot = False + if self.blitbox is None: # matplotlib is in rgba byte order. QImage wants to put the bytes # into argb format and is in a 4 byte unsigned int. Little endian # system is LSB first and expects the bytes in reverse order @@ -91,7 +92,7 @@ def paintEvent( self, e ): else: stringBuffer = self.renderer._renderer.tostring_argb() - qImage = QtGui.QImage(stringBuffer, self.renderer.width, + qImage = QtGui.QImage(stringBuffer, self.renderer.width, self.renderer.height, QtGui.QImage.Format_ARGB32) p = QtGui.QPainter(self) @@ -101,23 +102,21 @@ def paintEvent( self, e ): if self.drawRect: p.setPen( QtGui.QPen( QtCore.Qt.black, 1, QtCore.Qt.DotLine ) ) p.drawRect( self.rect[0], self.rect[1], self.rect[2], self.rect[3] ) - p.end() - # we are blitting here else: - bbox = self.replot + bbox = self.blitbox l, b, r, t = bbox.extents w = int(r) - int(l) h = int(t) - int(b) t = int(b) + h - reg = FigureCanvasAgg.copy_from_bbox(self, bbox) + reg = self.copy_from_bbox(bbox) stringBuffer = reg.to_string_argb() qImage = QtGui.QImage(stringBuffer, w, h, QtGui.QImage.Format_ARGB32) pixmap = QtGui.QPixmap.fromImage(qImage) p = QtGui.QPainter( self ) p.drawPixmap(QtCore.QPoint(l, self.renderer.height-t), pixmap) p.end() - self.replot = False + self.blitbox = None self.drawRect = False def draw( self ): @@ -133,22 +132,11 @@ def blit(self, bbox=None): """ Blit the region in bbox """ - - self.replot = bbox + self.blitbox = bbox l, b, w, h = bbox.bounds t = b + h self.repaint(l, self.renderer.height-t, w, h) - def copy_from_bbox(self, *args): - """ - If a draw() has been called but the update() has not - occurred, draw into the agg canvas before copying. - """ - if self.replot: - FigureCanvasAgg.draw(self) - self.replot = False - return FigureCanvasAgg.copy_from_bbox(self, *args) - def print_figure(self, *args, **kwargs): FigureCanvasAgg.print_figure(self, *args, **kwargs) self.draw() From b2431ad202f9aa9f8f65a1a88af32d126c862b5d Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 6 Oct 2011 10:15:52 -0400 Subject: [PATCH 194/214] Fix crashing when opening the Qt4 figure editor. --- lib/matplotlib/backends/backend_qt4.py | 2 +- lib/matplotlib/lines.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 277f0d82f6f3..8d4f0d424d6d 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -446,7 +446,7 @@ def edit_parameters(self): fmt += ": %(ylabel)s" fmt += " (%(axes_repr)s)" elif ylabel: - fmt = "%(axes_repr)s (%(ylabel)s)" % ylabel + fmt = "%(axes_repr)s (%(ylabel)s)" else: fmt = "%(axes_repr)s" titles.append(fmt % dict(title = title, diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index b57704024265..315796dbf3f8 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -563,7 +563,7 @@ def get_drawstyle(self): return self._drawstyle def get_linestyle(self): return self._linestyle def get_linewidth(self): return self._linewidth - def get_marker(self): return self._marker + def get_marker(self): return self._marker.get_marker() def get_markeredgecolor(self): if (is_string_like(self._markeredgecolor) and @@ -746,7 +746,7 @@ def set_marker(self, marker): %(MarkerAccepts)s """ self._marker.set_marker(marker) - + def set_markeredgecolor(self, ec): """ Set the marker edge color From 404a8d82c67ed12f0b247559a4a34376437601f8 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Thu, 6 Oct 2011 10:01:09 -0500 Subject: [PATCH 195/214] merge v1.1.x into master --- lib/matplotlib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index fa4d0084a7cd..316022ce0541 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -99,7 +99,7 @@ """ from __future__ import generators -__version__ = '1.1.0' +__version__ = '1.1.x' import os, re, shutil, subprocess, sys, warnings import distutils.sysconfig From 0fc9830fe946f6221e9ceff2910cd0c2118b0965 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 6 Oct 2011 11:55:41 -0400 Subject: [PATCH 196/214] Fix font sizes when displaying SVGs with fonttype "none" or "svgfont" in Firefox. Closes #510. --- lib/matplotlib/backends/backend_svg.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 7ac7ce87b1c5..b6542eecba63 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -331,7 +331,7 @@ def _get_hatch(self, gc, rgbFace): else: _, oid = oid return oid - + def _write_hatches(self): if not len(self._hatchd): return @@ -445,7 +445,7 @@ def _write_clips(self): writer.element('rect', x=str(x), y=str(y), width=str(w), height=str(h)) writer.end('clipPath') writer.end('defs') - + def _write_svgfonts(self): if not rcParams['svg.fonttype'] == 'svgfont': return @@ -926,7 +926,8 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): fontstyle = prop.get_style() attrib = {} - style['font-size'] = str(fontsize) + # Must add "px" to workaround a Firefox bug + style['font-size'] = str(fontsize) + 'px' style['font-family'] = str(fontfamily) style['font-style'] = prop.get_style().lower() attrib['style'] = generate_css(style) @@ -967,7 +968,8 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath): spans = {} for font, fontsize, thetext, new_x, new_y, metrics in svg_glyphs: style = generate_css({ - 'font-size': str(fontsize), + # Must add "px" to work around a Firefox bug + 'font-size': str(fontsize) + 'px', 'font-family': font.family_name, 'font-style': font.style_name.lower()}) if thetext == 32: From 9d0c4baa109d0f7ceac8d9e7a7e5a475c1fc27a0 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 9 Oct 2011 12:10:49 -0400 Subject: [PATCH 197/214] Add missing qt4 key bindings --- lib/matplotlib/backends/backend_qt4.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 277f0d82f6f3..3dbb1bbf54b5 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -120,7 +120,28 @@ class FigureCanvasQT( QtGui.QWidget, FigureCanvasBase ): keyvald = { QtCore.Qt.Key_Control : 'control', QtCore.Qt.Key_Shift : 'shift', QtCore.Qt.Key_Alt : 'alt', - QtCore.Qt.Key_Return : 'enter' + QtCore.Qt.Key_Return : 'enter', + QtCore.Qt.Key_Left : 'left', + QtCore.Qt.Key_Up : 'up', + QtCore.Qt.Key_Right : 'right', + QtCore.Qt.Key_Down : 'down', + QtCore.Qt.Key_Escape : 'escape', + QtCore.Qt.Key_F1 : 'f1', + QtCore.Qt.Key_F2 : 'f2', + QtCore.Qt.Key_F3 : 'f3', + QtCore.Qt.Key_F4 : 'f4', + QtCore.Qt.Key_F5 : 'f5', + QtCore.Qt.Key_F6 : 'f6', + QtCore.Qt.Key_F7 : 'f7', + QtCore.Qt.Key_F8 : 'f8', + QtCore.Qt.Key_F9 : 'f9', + QtCore.Qt.Key_F10 : 'f10', + QtCore.Qt.Key_F11 : 'f11', + QtCore.Qt.Key_F12 : 'f12', + QtCore.Qt.Key_Home : 'home', + QtCore.Qt.Key_End : 'end', + QtCore.Qt.Key_PageUp : 'pageup', + QtCore.Qt.Key_PageDown : 'pagedown', } # left 1, middle 2, right 3 buttond = {1:1, 2:3, 4:2} From 273da521129d95ff33949d7881ab303b1121c51c Mon Sep 17 00:00:00 2001 From: Paul Ivanov Date: Tue, 11 Oct 2011 12:19:58 -0500 Subject: [PATCH 198/214] fixed ipython links --- INSTALL | 2 +- doc/_templates/index.html | 2 +- doc/devel/gitwash/known_projects.inc | 2 +- doc/users/artists.rst | 2 +- doc/users/credits.rst | 4 ++-- doc/users/shell.rst | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/INSTALL b/INSTALL index 08fc3ab05629..87c49511c57c 100644 --- a/INSTALL +++ b/INSTALL @@ -47,7 +47,7 @@ progress:: matplotlib requires numpy version 1.1 or later. Although it is not a requirement to use matplotlib, we strongly encourage you to install -`ipython `_, which is an interactive +`ipython `_, which is an interactive shell for python that is matplotlib-aware. Next, we need to get matplotlib installed. We provide prebuilt diff --git a/doc/_templates/index.html b/doc/_templates/index.html index 351c132eaa17..5e47109fe9e9 100644 --- a/doc/_templates/index.html +++ b/doc/_templates/index.html @@ -9,7 +9,7 @@

intro

publication quality figures in a variety of hardcopy formats and interactive environments across platforms. matplotlib can be used in python scripts, the python and ipython shell (ala + href="http://ipython.org">ipython shell (ala MATLAB®* or Mathematica®` list. In the interactive `ipython -`_ session below, you can see that the +`_ session below, you can see that the ``Axes.lines`` list is length one and contains the same line that was returned by the ``line, = ax.plot...`` call: diff --git a/doc/users/credits.rst b/doc/users/credits.rst index a8b24b6c7e89..d1a6200c19b8 100644 --- a/doc/users/credits.rst +++ b/doc/users/credits.rst @@ -94,7 +94,7 @@ Fernando Perez has provided numerous bug reports and patches for cleaning up backend imports and expanding pylab functionality, and provided matplotlib support in the pylab mode for `ipython - `_. He also provided the + `_. He also provided the :func:`~matplotlib.pyplot.matshow` command, and wrote TConfig, which is the basis for the experimental traited mpl configuration. @@ -149,7 +149,7 @@ Nicolas Young sampled images. The `brainvisa `_ Orsay team and Fernando Perez - added Qt support to `ipython `_ in pylab mode. + added Qt support to `ipython `_ in pylab mode. Charlie Moad diff --git a/doc/users/shell.rst b/doc/users/shell.rst index 6ec60336be37..6f0a124b6a7b 100644 --- a/doc/users/shell.rst +++ b/doc/users/shell.rst @@ -23,7 +23,7 @@ python shell. Ipython to the rescue ===================== -Fortunately, `ipython `_, an enhanced +Fortunately, `ipython `_, an enhanced interactive python shell, has figured out all of these tricks, and is matplotlib aware, so when you start ipython in the *pylab* mode. From 78ed37c76cbf8920def023b51d16b4a5398c32a6 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Tue, 11 Oct 2011 12:32:46 -0500 Subject: [PATCH 199/214] bumb version string; change python 2.4 to 2.6 dependency --- INSTALL | 6 +++--- doc/devel/coding_guide.rst | 3 +-- doc/users/whats_new.rst | 2 +- lib/matplotlib/__init__.py | 2 +- setup.py | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/INSTALL b/INSTALL index 08fc3ab05629..119bf99a8896 100644 --- a/INSTALL +++ b/INSTALL @@ -54,7 +54,7 @@ Next, we need to get matplotlib installed. We provide prebuilt binaries for OS X and Windows on the matplotlib `download `_ page. Click on the latest release of the "matplotlib" package, choose your python -version (e.g., 2.5, 2.6 or 2.7) and your platform (macosx or win32). +version (e.g., 2.6 or 2.7) and your platform (macosx or win32). If you have any problems, please check the :ref:`installing-faq`, search using Google, and/or post a question to the `mailing list `_. @@ -179,8 +179,8 @@ libraries themselves. This does not build matplotlib, but it does get the install the build dependencies, which will make building from source easier. -:term:`python` 2.4 (or later but not python3) - matplotlib requires python 2.4 or later (`download `__) +:term:`python` 2.6 (or later but not python3) + matplotlib requires python 2.6 or later (`download `__) :term:`numpy` 1.1 (or later) array support for python (`download diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst index 0c71085acad2..34ea7ca6f7e2 100644 --- a/doc/devel/coding_guide.rst +++ b/doc/devel/coding_guide.rst @@ -17,8 +17,7 @@ in mind. and consider posting to `matplotlib-devel `_ -* Are your changes python2.4 compatible? We still support 2.4, so - avoid features new to 2.5 +* Are your changes python2.6 compatible? We support python2.6 and later * Can you pass :file:`examples/tests/backend_driver.py`? This is our poor man's unit test. diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 4d293b802086..d066ee326709 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -9,7 +9,7 @@ This page just covers the highlights -- for the full story, see the .. note:: Matplotlib version 1.1 is the last major release compatible with Python - versions 2.4 to 2.7. The next major release will support + versions 2.4 to 2.7. matplotlib 1.2 and later require versions 2.6, 2.7, and 3.1 and higher. .. _whats-new-1-1: diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 316022ce0541..2ca24a66e0fa 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -99,7 +99,7 @@ """ from __future__ import generators -__version__ = '1.1.x' +__version__ = '1.2.x' import os, re, shutil, subprocess, sys, warnings import distutils.sysconfig diff --git a/setup.py b/setup.py index 2f138218881d..31241ce78759 100644 --- a/setup.py +++ b/setup.py @@ -28,8 +28,8 @@ import sys major, minor1, minor2, s, tmp = sys.version_info -if major==2 and minor1<4 or major<2: - raise SystemExit("""matplotlib requires Python 2.4 or later.""") +if major==2 and minor1<6 or major<2: + raise SystemExit("""matplotlib requires Python 2.6 or later.""") import glob from distutils.core import setup From aad1d26000e75b4b60e5d8f271ba941c4934a6c3 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Tue, 11 Oct 2011 12:45:12 -0500 Subject: [PATCH 200/214] added pytz 2011k --- lib/pytz/__init__.py | 10 ++++++- lib/pytz/tests/test_tzinfo.py | 2 +- lib/pytz/tzinfo.py | 37 ++++++++++++++++++++++-- lib/pytz/zoneinfo/Africa/Cairo | Bin 9371 -> 1901 bytes lib/pytz/zoneinfo/Africa/Casablanca | Bin 558 -> 586 bytes lib/pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 229 -> 229 bytes lib/pytz/zoneinfo/Africa/Juba | Bin 0 -> 669 bytes lib/pytz/zoneinfo/Africa/Kampala | Bin 269 -> 269 bytes lib/pytz/zoneinfo/Africa/Nairobi | Bin 269 -> 269 bytes lib/pytz/zoneinfo/America/Goose_Bay | Bin 3203 -> 3193 bytes lib/pytz/zoneinfo/America/Havana | Bin 2411 -> 2411 bytes lib/pytz/zoneinfo/America/Kralendijk | Bin 0 -> 194 bytes lib/pytz/zoneinfo/America/Lower_Princes | Bin 0 -> 194 bytes lib/pytz/zoneinfo/America/Metlakatla | Bin 2264 -> 717 bytes lib/pytz/zoneinfo/America/Resolute | Bin 8554 -> 1916 bytes lib/pytz/zoneinfo/America/Santiago | Bin 9227 -> 9227 bytes lib/pytz/zoneinfo/America/St_Johns | Bin 3648 -> 3638 bytes lib/pytz/zoneinfo/Asia/Anadyr | Bin 1931 -> 1183 bytes lib/pytz/zoneinfo/Asia/Gaza | Bin 2285 -> 1534 bytes lib/pytz/zoneinfo/Asia/Hebron | Bin 0 -> 1562 bytes lib/pytz/zoneinfo/Asia/Irkutsk | Bin 1967 -> 1203 bytes lib/pytz/zoneinfo/Asia/Istanbul | Bin 2721 -> 2721 bytes lib/pytz/zoneinfo/Asia/Kamchatka | Bin 1915 -> 1167 bytes lib/pytz/zoneinfo/Asia/Krasnoyarsk | Bin 1946 -> 1182 bytes lib/pytz/zoneinfo/Asia/Magadan | Bin 1947 -> 1183 bytes lib/pytz/zoneinfo/Asia/Novokuznetsk | Bin 1968 -> 1220 bytes lib/pytz/zoneinfo/Asia/Novosibirsk | Bin 1944 -> 1196 bytes lib/pytz/zoneinfo/Asia/Omsk | Bin 1946 -> 1182 bytes lib/pytz/zoneinfo/Asia/Sakhalin | Bin 1961 -> 1213 bytes lib/pytz/zoneinfo/Asia/Vladivostok | Bin 1961 -> 1197 bytes lib/pytz/zoneinfo/Asia/Yakutsk | Bin 1946 -> 1183 bytes lib/pytz/zoneinfo/Asia/Yekaterinburg | Bin 2000 -> 1252 bytes lib/pytz/zoneinfo/Atlantic/Stanley | Bin 1993 -> 1965 bytes lib/pytz/zoneinfo/Canada/Newfoundland | Bin 3648 -> 3638 bytes lib/pytz/zoneinfo/Chile/Continental | Bin 9227 -> 9227 bytes lib/pytz/zoneinfo/Chile/EasterIsland | Bin 8989 -> 8989 bytes lib/pytz/zoneinfo/Cuba | Bin 2411 -> 2411 bytes lib/pytz/zoneinfo/Egypt | Bin 9371 -> 1901 bytes lib/pytz/zoneinfo/Europe/Istanbul | Bin 2721 -> 2721 bytes lib/pytz/zoneinfo/Europe/Kaliningrad | Bin 2233 -> 1494 bytes lib/pytz/zoneinfo/Europe/Kiev | Bin 2057 -> 1316 bytes lib/pytz/zoneinfo/Europe/Minsk | Bin 2067 -> 1328 bytes lib/pytz/zoneinfo/Europe/Moscow | Bin 2226 -> 1464 bytes lib/pytz/zoneinfo/Europe/Samara | Bin 2078 -> 1330 bytes lib/pytz/zoneinfo/Europe/Simferopol | Bin 2113 -> 1372 bytes lib/pytz/zoneinfo/Europe/Uzhgorod | Bin 2077 -> 1336 bytes lib/pytz/zoneinfo/Europe/Volgograd | Bin 1982 -> 1234 bytes lib/pytz/zoneinfo/Europe/Zaporozhye | Bin 2085 -> 1344 bytes lib/pytz/zoneinfo/Pacific/Apia | Bin 268 -> 343 bytes lib/pytz/zoneinfo/Pacific/Easter | Bin 8989 -> 8989 bytes lib/pytz/zoneinfo/Turkey | Bin 2721 -> 2721 bytes lib/pytz/zoneinfo/W-SU | Bin 2226 -> 1464 bytes lib/pytz/zoneinfo/iso3166.tab | 10 +++++-- lib/pytz/zoneinfo/zone.tab | 12 +++++--- 54 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 lib/pytz/zoneinfo/Africa/Juba create mode 100644 lib/pytz/zoneinfo/America/Kralendijk create mode 100644 lib/pytz/zoneinfo/America/Lower_Princes create mode 100644 lib/pytz/zoneinfo/Asia/Hebron diff --git a/lib/pytz/__init__.py b/lib/pytz/__init__.py index f6bcf100d5a5..c4a3462740ae 100644 --- a/lib/pytz/__init__.py +++ b/lib/pytz/__init__.py @@ -9,7 +9,7 @@ ''' # The Olson database is updated several times a year. -OLSON_VERSION = '2011c' +OLSON_VERSION = '2011k' VERSION = OLSON_VERSION # Version format for a patch release - only one so far. #VERSION = OLSON_VERSION + '.2' @@ -544,6 +544,7 @@ def _test(): 'Africa/Gaborone', 'Africa/Harare', 'Africa/Johannesburg', + 'Africa/Juba', 'Africa/Kampala', 'Africa/Khartoum', 'Africa/Kigali', @@ -658,10 +659,12 @@ def _test(): 'America/Kentucky/Louisville', 'America/Kentucky/Monticello', 'America/Knox_IN', + 'America/Kralendijk', 'America/La_Paz', 'America/Lima', 'America/Los_Angeles', 'America/Louisville', + 'America/Lower_Princes', 'America/Maceio', 'America/Managua', 'America/Manaus', @@ -772,6 +775,7 @@ def _test(): 'Asia/Dushanbe', 'Asia/Gaza', 'Asia/Harbin', + 'Asia/Hebron', 'Asia/Ho_Chi_Minh', 'Asia/Hong_Kong', 'Asia/Hovd', @@ -1118,6 +1122,7 @@ def _test(): 'Africa/Gaborone', 'Africa/Harare', 'Africa/Johannesburg', + 'Africa/Juba', 'Africa/Kampala', 'Africa/Khartoum', 'Africa/Kigali', @@ -1220,9 +1225,11 @@ def _test(): 'America/Juneau', 'America/Kentucky/Louisville', 'America/Kentucky/Monticello', + 'America/Kralendijk', 'America/La_Paz', 'America/Lima', 'America/Los_Angeles', + 'America/Lower_Princes', 'America/Maceio', 'America/Managua', 'America/Manaus', @@ -1325,6 +1332,7 @@ def _test(): 'Asia/Dushanbe', 'Asia/Gaza', 'Asia/Harbin', + 'Asia/Hebron', 'Asia/Ho_Chi_Minh', 'Asia/Hong_Kong', 'Asia/Hovd', diff --git a/lib/pytz/tests/test_tzinfo.py b/lib/pytz/tests/test_tzinfo.py index c4da6b58a07d..d8e5ddf33397 100644 --- a/lib/pytz/tests/test_tzinfo.py +++ b/lib/pytz/tests/test_tzinfo.py @@ -21,7 +21,7 @@ # I test for expected version to ensure the correct version of pytz is # actually being tested. -EXPECTED_VERSION='2011c' +EXPECTED_VERSION='2011k' fmt = '%Y-%m-%d %H:%M:%S %Z%z' diff --git a/lib/pytz/tzinfo.py b/lib/pytz/tzinfo.py index 2be4fb8425df..1bb57c250039 100644 --- a/lib/pytz/tzinfo.py +++ b/lib/pytz/tzinfo.py @@ -107,10 +107,33 @@ def localize(self, dt, is_dst=False): return dt.replace(tzinfo=self) def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime''' + '''Correct the timezone information on the given datetime. + + This is normally a no-op, as StaticTzInfo timezones never have + ambiguous cases to correct: + + >>> from pytz import timezone + >>> gmt = timezone('GMT') + >>> isinstance(gmt, StaticTzInfo) + True + >>> dt = datetime(2011, 5, 8, 1, 2, 3, tzinfo=gmt) + >>> gmt.normalize(dt) is dt + True + + The supported method of converting between timezones is to use + datetime.astimezone(). Currently normalize() also works: + + >>> la = timezone('America/Los_Angeles') + >>> dt = la.localize(datetime(2011, 5, 7, 1, 2, 3)) + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + >>> gmt.normalize(dt).strftime(fmt) + '2011-05-07 08:02:03 GMT (+0000)' + ''' + if dt.tzinfo is self: + return dt if dt.tzinfo is None: raise ValueError('Naive time - no tzinfo set') - return dt.replace(tzinfo=self) + return dt.astimezone(self) def __repr__(self): return '' % (self.zone,) @@ -192,6 +215,16 @@ def normalize(self, dt): >>> before = eastern.normalize(before) >>> before.strftime(fmt) '2002-10-27 01:50:00 EDT (-0400)' + + The supported method of converting between timezones is to use + datetime.astimezone(). Currently, normalize() also works: + + >>> th = timezone('Asia/Bangkok') + >>> am = timezone('Europe/Amsterdam') + >>> dt = th.localize(datetime(2011, 5, 7, 1, 2, 3)) + >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' + >>> am.normalize(dt).strftime(fmt) + '2011-05-06 20:02:03 CEST (+0200)' ''' if dt.tzinfo is None: raise ValueError('Naive time - no tzinfo set') diff --git a/lib/pytz/zoneinfo/Africa/Cairo b/lib/pytz/zoneinfo/Africa/Cairo index 0b0f374d52c4b7f1a819ce489da42c97a94443ca..d3730dfbc1d2c88298e08b2362b9d6de80a0cc5a 100644 GIT binary patch delta 51 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 JN`qi&`CsM}iS_^h diff --git a/lib/pytz/zoneinfo/Africa/Casablanca b/lib/pytz/zoneinfo/Africa/Casablanca index 28ab6bcc93a383298ad6ce72bc0955020b406e17..77b88cffa389c297821a5faf9d379cc72bcfe68a 100644 GIT binary patch delta 60 zcmZ3-a*AbwGNbfFl^hP=={p+yOnN>{oFF;*Eu;0sM?mq(Y>XEK7=QpI38E1S907%A B6w3er delta 38 ocmX@bvW{hfGNa@~m7K{RfYjy~M#;$nj29prOE#`>*AN3P00R09jsO4v diff --git a/lib/pytz/zoneinfo/Africa/Dar_es_Salaam b/lib/pytz/zoneinfo/Africa/Dar_es_Salaam index 3b81079f23bdc794780e3eea8d5a9c13f88c0819..720d76c8300f94058c0948bd257bd6ee59c56070 100644 GIT binary patch delta 57 qcmaFL_>^&ixyThpCPoGZl`9NDpk=_o!oZ-mX5s<4iJ8tgq*MWi91Pw7 delta 57 qcmaFL_>^&ixyWNiCPoGZl`9NDpk=_o!oZ+5cj5uLiJ8tgq*MWkRt(+% diff --git a/lib/pytz/zoneinfo/Africa/Juba b/lib/pytz/zoneinfo/Africa/Juba new file mode 100644 index 0000000000000000000000000000000000000000..20284ff94b9bb40c738448781e8191b492d73305 GIT binary patch literal 669 zcmcK1%_~Gv7=ZCJpJuKZjIS}wQO8*c zZH?&g_J>54DmH4W5*vH9@d+b!-M&uvQ<79=>#1Jxp7wOT#3gl`(&?KQX*e6VjTbS~ zw7aP@`_HDia&B8z?@jA$(YDQ8n)c$d&h{Oej?|IOB{od%?M`>TA4r#-)A@&WDO^?U z=uXKGhkkh?N)=ArjaC0($lW~et0ZTYo?i&m^kkV=ph|9kuiy_EKHaLN;AfWuNP=WR z(ja+|L`Wti6_N`{hGeVh(jobfgh)mtC6W_KieyF7B6*R-NMSdZ>%@{J#Mv`&O#D}UAtG(eI9RQH)3Pu0` delta 29 dcmeBW>SdZ>&6qsVMv`&v#D}UAtG(eI9RQJm3Pu0` diff --git a/lib/pytz/zoneinfo/Africa/Nairobi b/lib/pytz/zoneinfo/Africa/Nairobi index 933be64c1cfbb326c6d3ac5dd27c4f197181c1d8..72676bb987d485a91f0cf7386ce9f104130f49d8 100644 GIT binary patch delta 29 dcmeBW>SdZ>&3I*^jU?lmi4RpLR(r!aIsl++3q}9{ delta 29 dcmeBW>SdZ>&G>ktjU?mTi4RpLR(r!aIsl;o3q}9{ diff --git a/lib/pytz/zoneinfo/America/Goose_Bay b/lib/pytz/zoneinfo/America/Goose_Bay index 49ee49fda6a44bc104d37aa64bfb80868df6e173..f2a981849d1d546ed15149f2684a77eb99cd53c2 100644 GIT binary patch delta 663 zcmW;JKS-NV6o&E72832D4izkjkVO|8%peFA?B*WCOxof z`wFj&#<%qCa<9C5v7-H%78xkd>R@YF1}|fpsS8QwIHE(PMH%{0q1lTg8U9*t6C)?* zW;FNIzW;e>#yYR;_}aGl(D=`O99uOLm3wxwZP-lS|J7X6isa6Ab-F4m(+BJN`8FnB z3ZHc5G$OO}T{^d4A@k{%n*Vk!yQxsPl*c9mP2S}GUye|^apy!rQDK}E>H zNo|ljxky2RSW7qw;t(wn;^5@V^0$CO!9~+WR6;de1{mR-8%lSE2Uh?@Qm;OYJ}XA_FT0 zHZH&SOlthX4u0D(LoI*o@Y13gsrqg|45iHI!_Rgs7Bgel+d5G#GI6x3lSNUP+(~Qt zDwL18Hk~>s6wTD>^p8u)bUfDV>R;JP+*X2hh@VXh0DZFkDWD;bSAgBlew&4f+AR8e&q2H?XUi{XB=V474 PdD<9>R7NU8|8e&Q3ohoQ diff --git a/lib/pytz/zoneinfo/America/Havana b/lib/pytz/zoneinfo/America/Havana index f34e63a3a25e3bb45d854af2e213b4a380633238..b519c0947008a2f2704901487fd714bcbf7caba9 100644 GIT binary patch delta 25 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 diff --git a/lib/pytz/zoneinfo/America/Santiago b/lib/pytz/zoneinfo/America/Santiago index 453d78741e3ef7aa91a8cbfc6c75c609138ce411..a8cafe6a88993c1e006477f10b9e7dfabcc5a43a 100644 GIT binary patch delta 37 ncmeD7==RufmXZA!yMbRo(}B%b7)@BYfgA=P01F7S|BwLy{s;_{ delta 37 ncmeD7==RufmXUq>qYZu&WgIqNVKiao267mH04yNP{zC=;9Hb4Q diff --git a/lib/pytz/zoneinfo/America/St_Johns b/lib/pytz/zoneinfo/America/St_Johns index f5d2855c5b80a7c4d3c79d0f22c24c32e1eda161..27416c3797327dd0451404b37be7e866b46af759 100644 GIT binary patch delta 681 zcmW;JKS)COxui>p2MQ^#4gX?iDz|ME|ISeb_+v=w-m zn>siq6$jFEI5a#MA#TqgM}r6=qGOau&-?i;uOH9$eSh|9cWb}iEY0p#N=IKzJJ&Ac z@q-%enmd#yx2`naotOB(q9$6_Bys%L>g{hve;nD~>zsMIU9iuJbEa=)%RVpknEuqV z9oT3!FWNVC@O?st?k{OF9g|dLQimVa$nbfart7aH{i{Jo%8D|w6V}m_JsJCS*T%;W zj?6@++`jx$Fq7S4LOD`e2qw{16I>g#<&QA>ojCNI)c_*M&r4dRDs&3~FmSNGSxGY9~RcnhchrxM~-%ABkwI*4j4)wSK>T)z%CKI<_@f zHwSSnwIJ#yLAr`a7pIWn(4_<{oIwym&vWkbyZ3JI^FNH{qd#jaG6(;pXCSIiH-F2s z_Od=-IFJ|jike7nN#goMds|ne*A#4D-KOdLmAC!nCG&E3$G$4`n}KZB4j#9gAsMx= zx9^+b?sa|hsZB6}jD|sm`*bN{yOsC`$UYM#m~oWbAuM$N%ig#J8I^@$M{d zCKvwNsl6RDojkQOpR;DRb< z;B_647GBo_X@Yb?+8})}LnK}Zg~URFA<>XZ8n zWPT7DiH!tDq9fsv_{adr2wpb?GKSX;f{fyI!yw}z0|h}t5U>(ISPEGSSq%MZ=i&NX cFMvKLbeWQ2+n{ diff --git a/lib/pytz/zoneinfo/Asia/Anadyr b/lib/pytz/zoneinfo/Asia/Anadyr index a49b1688a55250be04ace8c43c507342bbddef5f..2841a6376d9f9694ab79586449398d15a57d20a5 100644 GIT binary patch delta 164 zcmeC?pU*i#T#$=_fdPa;zyXN4HfpdiPGYiWWSv~fWTwf$u;Ks%i;r&zgQK4#m?_1OW&WL}D{)^A{!-Cb(HfM4QD0vP;*{hzkI3ixxuw delta 880 zcmb`_Pe_w-9LMozHOP%H1<^W0bQ`+nhB!|$b_jyfG`C^tT2{Jpv%a;I&05bTDUu*t zmq_p+VTbS!MW8ni>TP%s=@3Lv&_Uu$i6?`8?+3bhlAiJK`tclg_`H8pp7A5k>#9AL zW%2S1o7c18bGz*JcQtx`=&N*$?`UV@k6y@p(ys6qjh$W6cdq7ezqjDv6M*50Ly&9>PYsrXSKXF+4TTkjhg-_GR z4{G{{S8wco*PClwI{0}_Gc)D5W>>z+(BpZ%^=4IWr(dXyy_Gv1b8@%;spNtaa_@9j zhO2Ti5_qB`8kcc-5@M*(!Zls8jpdFD?09k?^64{rpN< zSGbgOAN{wKW$iWH``<420h=Y+57`je5!n*i6WJ8m71>>LQl2O=UNk(fwOBq|aX ziHihAA|s(4O>88%qlu1$$I%8;p941lxdq5gKyCy6ryJqpznsS#ZI8xIg+hj|n7^$l P&>RT*+d@HXZ1VmENi6%T diff --git a/lib/pytz/zoneinfo/Asia/Gaza b/lib/pytz/zoneinfo/Asia/Gaza index 043a06ce737149130cb1bb2608d1a46ad0301965..063ed39e8d8c3c2a85331edad4ed6797109c0097 100644 GIT binary patch delta 83 zcmaDW_>X&nGGoj}l{iKz!3&~wvGd&bAIfp4`@*k!Y j#@Nk?%=?&_1TRchWK-n^$}#`}Sj9*7*vU;C!Hir0$MGP| delta 802 zcmZ|MOGs2v9LMo{FAa%B<{~IMw&(?hb9IO*G-wf7KAOyQ)G23Do2G}A$7+1^@IpkJ z2$Wk?aEQT0xCt@|B4`R15x7W*Hc=sMYE%7P1W_Q}?|`f59uA+&S^mBY%f6M4Zm>ru zH>PYaEcG+L=NfViy78fF_H{p>jon;n_IIt&O#@+dpni)qx0R@a<;$fdI?1lbbr%Jb8dZJpRXJ@7o42VmRvL0&sX)pkBk|dPV1pJb!K>ckG}Zyn7VYMM=syp ztFH9!mXV=ymxVTY!8}&*F%dEo zG8HlxG8r-(G95Bs!C*pUMr2B4PGnMKR%BZA*q0wRMs`NFM)pQFM|MZHNA@omG(b8O z3{oIDkR(VJBu#*4(T4{bA)Sy`NH3%r(hX^c^g|jV9Sa66k)B9Xq$|?avRum|Fb_mV vLL;$};7D{o7E1cLQ1L%^A{1X;TieoF5!>oU-EEasHC2&{ShX8*qs4y#g@ydh diff --git a/lib/pytz/zoneinfo/Asia/Hebron b/lib/pytz/zoneinfo/Asia/Hebron new file mode 100644 index 0000000000000000000000000000000000000000..841779271fe09b6cc431c49c162960bde52a47f8 GIT binary patch literal 1562 zcmZ|PTS(JU0LStF++4a*U{F+4R$AF*wX9ZlGtGG`r`{}TiHgdd)I_;&+-$I?;C2u zy^~WSKLW3#KL&$V-#B-;@6$7@zb`BLYi6#UwD-758mO1ay=}r%yHHNN_ft(e+9fA9 z4vJK9)}C_knwVO2Q%>7dBGOX5GQG?%rd!$e4DS~;<9)N7+1{iw9ysk;Z#%^7x>Pym z&Q>+|s6+bB6{vZYb@u!{vy{K^k@UBWPz$!?i_Dw`u`n+~ESh>rEKc``fa9R~`eJ$M;s(34+^b5D z{IV>^-z&ip=W;oRy&MUNT=Bj&^vtqm`yKkvJ8_DB;l0beCYvWCW6y)ZkQEHB4_QTd z`qrAmxAY0cpU?>X5jUq&-@G3)sL#H;#p97VA(KL8g-i>X7cwzqX2{f#xgnE7W@psX zL*{4H6GUc+Oc9wQGD&2X$TX38A`?YsicA%mD>7MRwnjZ&WWGi{VPwY0l=-DFXQQ4p zGHYbo$h?t>BQr;)j?5jIJTiM^`pEo|1dt4jIt3&LBnc!7Bn>1FBoQPNBo!nVBpIX5 z21y6W2T2IY2uTUa$*7Y;vO>}_>b#J|kj#+Oklc{uknE83ko=GYkqnU(ksOgEkt~fm zO(ahwQ6y6&RU}s=StMH|U8By|s1yDtTW3O?E73LVmEd%9#rxLKGd+eDepIYpU2?49 dB=aQJaEd9}wXTGcDsWI>^<^W)ap#dZQMB!_0&qMG+%KL6~LEXlmK`kxe<1spX`WT?wLs z2G5Ey9$MHqp{*B@rP+?jmRrB@uy(sQa8%bl~tioaOT`ls;QKwb_i!ZgGrz z=xJOI53JIrTbty_(XG;)EtbUgGD$XkmX?aI(pvReT7NA_+qzHMwm2j0Kj*dM`5ig- zKCj0gO>5`eO+DdGY3go9yHdm2J#j;N;z{l8?3a@p>$Gq8K{@3lBwZPi^p{#W{W~OQ z-mI7Yr5}>Xue3<^Rk@zM{!s=VFYCGVOBuZOPKTO4=y2bho{zoI3;XWtNa&&FA_d7U zyE)5x8GCs3cFD6ZcYP^?$d-%bFU;lm-HW zlYyZ3#Oyb@!gmuYas&RM1X2Sjf>c4uAa#&JNF}6{)vtvVv-;JLa!5U-Ao>+u`yeGB z_~bfKQaMk^6rX#Fa;mXflPwTf=q+VgG_|XgiM9Z zg-mAkXG5m5`tub=OaNz~2vYz6 diff --git a/lib/pytz/zoneinfo/Asia/Kamchatka b/lib/pytz/zoneinfo/Asia/Kamchatka index 0c5a85dbb8cc8f5d1693fe434559a30c4ce660cd..090bf488957b2fa56419a25c2b378ea9b5ce366c 100644 GIT binary patch delta 114 zcmey(*UvdYT#%E2fdPa;zyXLkH)^mjPGYiWWSPv%ZotC8u;RdEYj#N{Muy3InB*~) bZ+^qX!i1?_m=RO9uYl&()jwjEC2c=di=){d;=)U(S^GjN9RG z@bV0r*ZsE0<+K_X^7K;gHwiu7)28Tuy`0?E=E|=cu3y(k{s)bg%xQG*mA2%qNz3O6 zz4CWfuC6BZ+Ez+hUp$c5N?fj6T@s(EksI+kxtWS-Td-K#V?pgG$d=CPLhW)FY2sX# zCVqJI*8X?Bz41%Czieo7J`>TNk2}))a9R6af08?iX_bjL(jQuqyPc0@!2e9{)%M6> z?tl#WCUr<7GMv+`!<$ty^82EWE}xbA8J~_luh7(Du8xm*)q3(r)4N&0%9E##@=KSw z{OOlYZ~DEn;P7PcemY$zEEZ%pWIJR(WJ6>}WJ_dEWK(2UTeB^)udUe_*%{dy*&EH~ zmVID&J}^EK0EvKvKw=<4kSItPBn}eD)QGNZ#r6%NKpO!kZ%lV#aWI2c$M7z!E~IVW#qa$|JZ{DX;u39F+<&)Vgbf+Omt)-ndMumLKX^`dgjRH|qTLPF+jBTi4r1+WqsDbw9YK zp4T(B=juc2y?@F2f@$lYEZW}wGd3_jrF2u;_VpIDf7MnS+|;cDkpX2^ZdB&e79IRk zqeD;E=d2WuL6DBWFJ=ck{0eXP#?h;)5McezaqQvvyq1?8LSkmS1$sM&pk) z`t7_G7F<{1<**gMOlZtn?c|G$PF>Dv{7$n@7n2GuL{*CUO(j*#pYvq>brHYH^U@<; zMXBs>_w)C@`jL5o=RTG})yk@=AXp)LcG0?C0S!J%?c8D2=k19^}{NG2o|k_$vqZ diff --git a/lib/pytz/zoneinfo/Asia/Magadan b/lib/pytz/zoneinfo/Asia/Magadan index 98674195508ab6407dc8e32f7c85e616c299c820..e3c76b57f59f590e82cae053dafd15140a0c6322 100644 GIT binary patch delta 73 zcmbQuKc91gGNZ#r6%NKpO!kZ%lV#aWI2c$M7*-r$b$&Jxr^A9EtCajXmoLs(+ K?jgE{MqB`P-4JpB delta 807 zcmbu+&r8#B9LMo}Q(}%N4^ns#2|Yxvxnb%lhKGJYt}M4<>YQmhbu-^(6Sda&k|c#t z&5Id$5Ya=}A`$fF!Mu$Q5*-2w3Oan}Wd=%2FAyR9OZ>vhgm zm|e0iS?LdZmivh9G9P7-I!Ga;5>g7Og%m@oA>|xRJ*1$csfd(BY9d9^RJEOhv^t*7 diff --git a/lib/pytz/zoneinfo/Asia/Novokuznetsk b/lib/pytz/zoneinfo/Asia/Novokuznetsk index 76bace90fb08d5ae7de8bbe571bccf8d516626bc..f78c1f88bf659dc263bc62a3eccd1d77f1c9507f 100644 GIT binary patch delta 123 zcmdnMe}r>_xF9zJ0|N+yfCCV7Z`5F6oWx|$$TeAm-G+sMA*o>UdL}gS8 z(cog?Acs~2ZC^-4MASi)h6ZsF2WilnqJHm3+?t~2c<%M^4A1a+|JKr1uFhp&_qbdx zZmyWQJ*)YtmR+^nEY;crp({kw7(?} z&kps`r=&FRebL7Yo7(d6t+v|B8lIolw(zXB#}}oeY*0H}rlc#UPP8@qw4)gt85|iM86M5} zw(~#%UQhukfz&{XAXShuNFAgQQVA*LXlfzFkZMRd>|3(4oCgZ>f{I8LP`a%1CKPQyVGnXsRRSalF9f=Yb=D90TMiAjbj!(~-#MTNjt7syYN37 z8WM+=3Wr0|B5?bH5D`%hQaCh(OE`#wW=q)b{e!mff#1D;JlyiUKNnCYH z{Gm7AtxCuCrrv!1Q9Iwh)GjZh@u&0J9beR2sTb07bzFNpAIt6HChe;lkbd8oB#LSz z@v~6|{sd+4LqvwY2V{69zePsgU(`GE$1?gVN5>L7GX7{^CmN3QZr_&P3xCteYwJ37 zZbOryFOoc1*6F~SOmC%hWnuj6|E^OVdj%}HvtRUXWAiMLoO>9A`~R-QfGZXiA3 zmZu+P75@8t$N686H^1GSGah+}f`mchAc2rbNGK#05)6rEHQ|tWRud43h=fF9q6zBR z3sreRS)?vf7^#euMrtF)k?Kf!q`uWGfUJNlfvkbUD_*|6unI3&23ZGL2w4eP3Rw$T z3|S3X4q4A?7DQIGnkA7nakkV<%7s~xX_0x6iSe|VOZbC*vg_(&(M#p#w>cWDjfAd* N!ok|IFkX&i{{@Q>;&A`~ diff --git a/lib/pytz/zoneinfo/Asia/Omsk b/lib/pytz/zoneinfo/Asia/Omsk index f47337f62f5a5a3e2d2bf540a6599d61a6eb2b22..a3dbb4bb1c5ad68e460fde645e3303b804932535 100644 GIT binary patch delta 72 zcmbQmKaX>QGNZ#r6%NKpO!kZ%lV#aWI2c$M7?KJYIVW#qa$|JZ{DX;u39F14$ delta 806 zcmbu+%S)6|7{~EBBJnDrEfQDeLQ&9h8W}BIh|fY>NaJnB`(?~a<7M(vji@=kD{~VP zOq&XFQ!xt>tq9sZAV@@%izr&Oh&Iu}T69@Sp6~k)wCIKNehz2(`##9Imw&s&BzH?4 zTX`}4E*J>Qo8 zcY8Xp`AP?$J<=g}OJjG|bvU-6mr@U9q+w1+2XD$)afgoAPsn9wR^mm?693vR6GwiT zd>N9dPkAz(Dd?2MeuZ9H|06SxPwH&^qs*-x>U`TTy*hrN*McAPdeak4o_e7Rfw!{o z~zLlFv+Lijg#g2?8h?5I>^=Yh diff --git a/lib/pytz/zoneinfo/Asia/Sakhalin b/lib/pytz/zoneinfo/Asia/Sakhalin index b1fda9ac7ca3f25eba81b3f9fb4e765335069819..f5105a363cfd6639e28553307f40229e09de5967 100644 GIT binary patch delta 117 zcmZ33x*Utm(e cRKJ;#nTH9B1`$TEnP7q|*wH&g*U*p)07`xm5C8xG delta 801 zcma)(OGs2<7>3^?6^;zuh@v1Af)cdph-7UfgItN1nsKtcm1a|oQ&~1RQ+B=<(V~dx z2-Qkjgh&@k!kxGhX;Uu5RjzYo5z?j>{m)tErU(9cKMu2co|)L>mM6Qm#U$|{?_TUf zWvLgmyxFJL+;?kxv{5Hd$8{?EP06}drJ6peedmJGRj-x)HKmRn^VYF6rZa1kc6K_i z&c%n;HU8APKjy3_7`EQARy)_5w)3Nd>N|GS`ny|np?r@G)cd+vdPJGM+m%__txJE_ zbb0=_u6$imc4E0*gL6ME_h436UoG0T%u8LrKW#&8Gj?O(x!v@~ZMd;$x3=E1eBzn% zKl*KCb3r2ujaFFgRPp@*yZyOdcV3*(=(}>=E$mnD*i-0x4PnEE_&;w`IONrZZ@r4} zi&wGU$5ctYB)|?%052?V06%~uz!TsK@C7)F)_DWmMeF6421K*S286Rn2gC#Nqjdp*2tWuR24p9K<>(*^2VsCXEP;SXETLFpu>@m@#uAPt zUbHSCOT=hhNS2sTta3#;s0x$?>H>w~e=1i-|Kz7EdAuogu*P?jOjS46CJrb3>gF1s IJycuv7l9(mZ~y=R diff --git a/lib/pytz/zoneinfo/Asia/Vladivostok b/lib/pytz/zoneinfo/Asia/Vladivostok index 514489555fb29d07c65db45a44725e5c7ba38fe5..1cae6d0fd9880e7de01c294cbecf820dde247f9f 100644 GIT binary patch delta 73 zcmZ3b$(PY#^M57|CajWLoLpf( Kjv=~+hFk!YToD=o delta 764 zcma)(O-NK>7)GC46O17i5m7<7FbYz}EB3cB3365blsZ|aQ>jfgj`pL2GiCQ}5iOF4 zu28M4MTlt8AMT`8NSlxlSGlg0Mu?jt`p#Xr?!d=+`IhH-RWz~bQJFXRc6Zzh8m7wB zm|eD}kqtU|x>%<&-_?9@NiD}et99F)lI4?1uD(;-)>&&?7}c4T2|GKTQ~Ue_J2&>& zIzD8rGZ?VcXrrA^CGEm+uP)Xewyur_b(ik6o*G}5;)j&pwMFS4J9PQaimuH5*41wd z%8W0zs`t|`%ijN}zL)dXpMIfh_onT7(~RBdd1^QPF&n5W*x=^7mP117<&>^M6b{R8s(==VCY15{a)rQU=Uywo% zQg2unyBLA#!K_G%ZXF_oP&!mzqC<2Dgz{jW68t>B|A2?S@cBMIe2%Z@g7=|M{dVTX z36JeGtyIg|;XQ4hJ1pnUmr6_ekHqW$Ng}!>ttH>2t@4eu{e3I#M?P!&m&ekv`&uu& zx+9&R=Cy0#ktWy1^`bMa-4Bv_sk={mCUer;7}3kgF6lc~q5Y>D-E$#xpDWMjx>MJoBdDpR_LkT4$o>v?rS!< zDA}D69X&K7qaWis_G?gb&+Bx2Gb$7FEi$=UB~xRy;@tB|K43TILxn{Lo*}!|V|y)Y zO0B~DvK_HAFMr#f0>?5R%OL9@3n42ZOCf6^iy^Ba%ek8MkOf`MipY}4n#iJPR(0G9 z)AGQ)$i&FZ$kfQ($mGcE$n?nkNCH=r0ZD=6K$2j3$=P-5zO#LRXU!N$F~GB1th|AcdbxF9bB0|N+yfCCWoZq#65oWx|$$TQi3-GhaJAtYgP9lHh}BS--pVAHr+ VoSB6QQ>PfJPOeB-?+{%xE&v>b4|)Iq delta 815 zcma*kO-NKx7>Dt>YN9fwEmR1jg%FYBIH7|ggtQO?vtD(yvC^@09L@2obnt7uix9#> zg0V#)gqtvkD3ulx2|qX z9G)R_+;7jNSoYOdU2?70ukyHBYOmKxU9?c@OG_khB~u!5bEL80k2LP?Nih4k2EVRL z)6Q?b@$S9c{PJ0EJ^!Z7ON-iKFKcM#skVk@^>%zg?o>=@Tl0*xpJ~HJ$RU7s$=-Hklyp3iTP=xUkvJUk}7FHUJ+V4l29jsi@ zp{$P@^KM9N`=t(__#ngjNJqBjWb{psj;%eA@n=&Ke;t;Ik*L_yRg&;n6^W4L{^z77 zqSocavUT=w24{=^O|zJjl#*ogH~SzPAv+;kA$uX4A-f^lA^SO+4Uruk&6dcX$fn4y zXtuST3j_0lk&&U1v5~=%(UIYi@sR*X1SEu`iGc(`q99?gd*04>E(GEQk&sYGEF>5b z4GD+DLjocZk&uoiCKA-qL`A~lXo0EAg~CW>q%=|+k5c?RA09p#O_kMwLcjT~4|r;d Py?(FHQ**(GMa3BhjM(jY diff --git a/lib/pytz/zoneinfo/Atlantic/Stanley b/lib/pytz/zoneinfo/Atlantic/Stanley index 4cb6097cbeb0e9abef40c8b640dd82863f50273b..d7da723f7ec8215c55ce3fcf827deabc0dd49203 100644 GIT binary patch delta 37 tcmX@fzm|W3GGpaN6&c3O9*mxhlP5D}Fjj5;!(_v>*@IP#X>tO4CII6E3vU1b delta 57 zcmZ3>f0BQKGGp~d6&Xf$-&MsI{E~$?+cSDGPHtz)VyxNxiOGhE8zjyE1Ryz0R%xcm HPVCtL7i)COxui>p2MQ^#4gX?iDz|ME|ISeb_+v=w-m zn>siq6$jFEI5a#MA#TqgM}r6=qGOau&-?i;uOH9$eSh|9cWb}iEY0p#N=IKzJJ&Ac z@q-%enmd#yx2`naotOB(q9$6_Bys%L>g{hve;nD~>zsMIU9iuJbEa=)%RVpknEuqV z9oT3!FWNVC@O?st?k{OF9g|dLQimVa$nbfart7aH{i{Jo%8D|w6V}m_JsJCS*T%;W zj?6@++`jx$Fq7S4LOD`e2qw{16I>g#<&QA>ojCNI)c_*M&r4dRDs&3~FmSNGSxGY9~RcnhchrxM~-%ABkwI*4j4)wSK>T)z%CKI<_@f zHwSSnwIJ#yLAr`a7pIWn(4_<{oIwym&vWkbyZ3JI^FNH{qd#jaG6(;pXCSIiH-F2s z_Od=-IFJ|jike7nN#goMds|ne*A#4D-KOdLmAC!nCG&E3$G$4`n}KZB4j#9gAsMx= zx9^+b?sa|hsZB6}jD|sm`*bN{yOsC`$UYM#m~oWbAuM$N%ig#J8I^@$M{d zCKvwNsl6RDojkQOpR;DRb< z;B_647GBo_X@Yb?+8})}LnK}Zg~URFA<>XZ8n zWPT7DiH!tDq9fsv_{adr2wpb?GKSX;f{fyI!yw}z0|h}t5U>(ISPEGSSq%MZ=i&NX cFMvKLbeWQ2+n{ diff --git a/lib/pytz/zoneinfo/Chile/Continental b/lib/pytz/zoneinfo/Chile/Continental index 453d78741e3ef7aa91a8cbfc6c75c609138ce411..a8cafe6a88993c1e006477f10b9e7dfabcc5a43a 100644 GIT binary patch delta 37 ncmeD7==RufmXZA!yMbRo(}B%b7)@BYfgA=P01F7S|BwLy{s;_{ delta 37 ncmeD7==RufmXUq>qYZu&WgIqNVKiao267mH04yNP{zC=;9Hb4Q diff --git a/lib/pytz/zoneinfo/Chile/EasterIsland b/lib/pytz/zoneinfo/Chile/EasterIsland index 4a3cf389c390148b4293a85c15f1cc9e11f84abc..1f7bae5373b932a230b0922e7a76f373bb70596b 100644 GIT binary patch delta 37 ncmbR1HrH*#L`L>w>;`@TO$Rp5V4Tmw4dgHY0a(C^?Y0a6{(cO$ delta 37 ncmbR1HrH*#L`L@Mk2d&ClyTTRgK<6!H;}^s1YiLtw%alQ9U2Y9 diff --git a/lib/pytz/zoneinfo/Cuba b/lib/pytz/zoneinfo/Cuba index f34e63a3a25e3bb45d854af2e213b4a380633238..b519c0947008a2f2704901487fd714bcbf7caba9 100644 GIT binary patch delta 25 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 JN`qi&`CsM}iS_^h diff --git a/lib/pytz/zoneinfo/Europe/Istanbul b/lib/pytz/zoneinfo/Europe/Istanbul index a7c16e76d1743ccdf5f8b7e6f8ef761e23456cb1..864099556bc9875b7e9258af6c3b221d84c68eae 100644 GIT binary patch delta 25 ecmZ1|x=?fjBNKD~-3gmnnD()P8AsXgFaZF0fC={i delta 25 dcmZ1|x=?fjBNKC9kHBUYrhTkn#!>b=OaNz~2vYz6 diff --git a/lib/pytz/zoneinfo/Europe/Kaliningrad b/lib/pytz/zoneinfo/Europe/Kaliningrad index 98ebee9aad004b739691cfc3aa49201a975c26b4..fa6bab8620370007ccb2a308c44b84ba8b596286 100644 GIT binary patch delta 159 zcmdlfc#V6q1G6%xF9QPuKM>1p)G=Y4Y{KNj$TxW#QwSRagO&k<)MPGZDPcF)5TF7^ zMj!zsK{VrJLuNHm0U#fQLBJ1)L2RYXIm`u2lUvw*8Tlu(b3{SRk(->zA*T&72h|{u NUSz-pRHSRn1porG64L+x delta 842 zcmZ9JOGs2<7>2(yIaX$-i$R#kqD3tlXEcp25Vbk2Je4_KveYR}tuZf^qNbe>gDAT5 zN7QasWsp%MLYrt+f)FjFHeFUl5kv&hrl9}%SK!8@oG%YD_nH> zX39&Oo6-165zoVgXD6mQvLUw0e&X19dpwst?ThqBLSCT>qKcslq70%9q7I@Dq7b6d z(W->#bhJt#S{Z5~dYM)1{@;1#1+E#s8O|BrA?_LeAq^NEAT1z09BmUw7f2gOADEpC z1NT5DMk`1!Ml(n^Mmt77MngtNMoUIdN86Oq)zP+P^o66FY-C1gNNh-ONOb7Jf65EY wx@h5|%QxlGW^*-Kw!?mJL3w_*a0R}fF5m3?b?HPd~-Cf750urV-b88FCAKF%a3=jIv$ zQpv~&#*82u27nx(d3-=F2!nt#5QErin>Cpwm?pnub7JJ3oXGA6F;HppdUhpssDW5b O1PU^80Tt*Pa{&Omo)T^V delta 869 zcmajdO-NKx7>Dt>auFLUUV~xWG=go4ZaSt?izJF}wa6)((X7$z%a3vz(`uTr>;^$! zM7(f=a1kVkxCkkAGG=JT@e_El{?a7*{+dNjQ$r}c5j`wFC?`iwo^LZ zt7JLPqhIyd)@O3O>y4hM9+RHtY3;3e zqJ67X`@Y=M{=dU|@^wj1eaz^mdd)@b$)?1j;J!0^cUNB|@P5(0^V1VN%8VURdh69|cfghFEBz*La6 z7ozcia7a8PAQBM?iNr*LB2kgBNL;H4j6}AY&`4|?S#OGSp*m6?sgJw?Xy1Yz?)LDC uTfXGE?xw;IZp~)?_@CFnJd65%X2V9`PiMTAhT5juWL<;TQlGT9#^@r{rR5#~ diff --git a/lib/pytz/zoneinfo/Europe/Minsk b/lib/pytz/zoneinfo/Europe/Minsk index 6a45115571f2e2d4fec5ab364bc02d01e056930e..ba9971c6313838b0bd33ca5c8703d22a4b7d6bf1 100644 GIT binary patch delta 170 zcmbO%uz_oWxF`<;0|N+yfC~_V*h(991Q;g^FgY`FPwr%LVq;*?GGLIKe2`sE#?3VZ zq>_;lgnwG?wF%yiG#g~Z)#|rj% zmp@GgUUXo>=)s;=IdrpMYa532aCd{&ZEn`={;gVHwo`M-)tZ}6Xk&bfG`{oo$gfp$ zbo#R%oBb`vM;A%c)JJKKK1s`+7t-4DN=^*F*ONQOrLF0?wy(V*r?!u3N9iN&TysS` zzg*X@Kka(@bzaYW*sJ-mOucr$Y?HIs(%SPdl-{nDdhY5v>8nl2`HrP>p)!z*;aBMo ze#$_4i4OdjmBAHrIyf^eh3{{)IC)Ply?v}h_osCD$!)z{xU12vJ~i9C-KN(I{<+0Q zyAo3sr9j!!& zNJlFZB9tK&B9>XX?*BW(e84ipG{ZK-IK(=`Jj6bu0Hgw>grltiDFUeiDFgFkQN}$e z#Ha)*#i#`-#;C?9$Ee3B$f(FD>1b;*iaOe=jIyw}!RBQohGd4MhUA7WdCuQsM*P@+ r&NmPIeP+&2)bPg(?RhUO7KYi4Rbg0{O=hZ7n^G0YOl1X3SI7PW>qFJt diff --git a/lib/pytz/zoneinfo/Europe/Moscow b/lib/pytz/zoneinfo/Europe/Moscow index cf001a555feac1deb3f67ed9a6c0fb5ebfce8c96..6068f8b9e584385eb1096c4f9603da74aa3e4095 100644 GIT binary patch delta 72 zcmdlaxPyCwGNaE%6${46229?JJd-yv`EW4sGB8*;FbYnN=1`lg&1}x-yE&P;fN63y ZyALDpAJjiSbkzCBl!3jJTziw2 z>mTc7Fdu7^q1UZ?W3E!N%O~~bz&?@thjlnvp||>f>+M>jBMl$)PU$Bd4gZo+eWhb1 z?`7=W6CMBhQYKdBb#gN&Q%lP-{cKid#^=OY>=U=kG`cwx_{S}D^CliJL7(qf#8>S8 zF==!6c}Ia1I6m)C1gV0QLFyodkV;4?q!v=l>QzI^S-pBlL8Ky561|#^eUOw7vLb1b zyhvgsGm;v~jU-31Bk8SPeq;h<24o5x%sVmrU=lu<1(^n!2bl<&37HC+3z-a=4VljB z&4)~A^=3q-#EBYjPabTF?22rQ?2C5exBKI6slV{Qx7^@~ delta 878 zcmb`_J4{ny7>Dt;IFO216A3PaFnOWYLL-_GQWzLWEK*x4AeFo2T3&7qS5F);m>6TM z3l6d&gE63lurNxT(18#VaB^XRyaQ@9A>n(@MB+v~&FSyt3}^U1-$(ab&&%8k9*4uh z&6P5@XX#3&)2e#dT=ts05mDU{mWVu^XrN$mGUsmr;lbz8rr z{^wb3SlN~boBP^0cc}5@ulms1(x%r-+T66NEmIrP8hoQ|@kMFRpVW@BSMn%xRuXx` zlGvM&&ZC%geThr=_uJC55UiEn^{DpE6i9NuMEg54M4n#KfpESKcKp?$BBu^l?&^r= zho*dgB&DBqG{+ma_54E&$;%z72t}_4%zq^64F!BR NeSUAK$d5My?qdk7_nrU% diff --git a/lib/pytz/zoneinfo/Europe/Simferopol b/lib/pytz/zoneinfo/Europe/Simferopol index ebb63b4450b0ac035c09d064ab515eb016850ff1..08efa510178f2dcf5ef4d6ebb9e5f4bae7cc355d 100644 GIT binary patch delta 170 zcmX>oaEEJx_+$-c9!@s~1_oXrR@$f|!8loh$(503@?<6tHUr;t8^QoG TR2^z4R#Sn3j9fqky2e}p=n)j6 delta 882 zcmbW#J!n%=7>DtDO9s8E@>U4xVhXw_#x}K9J6Lq^R);29lh$fl>sLRtG1{sn>4$d^ zM2g4@SC9^Zf|L$YlvW)aL=kb2;!;%5#Ysd&P$>?A=Q-daP9_|FCpVDc|Ky$bL^K|& zbR37nYs?((iF?UvH^|(%rF)7+*?Z-pw(XzPeT81lZY^l8b(glsGun|{uN_M%?TocZ z=j&B^;Kw>S_~5(d7d`2^StZ@`pXE^SO?s{^$l;zvIWqA{k8Xb`$GTtY@tP^=ZJyP> zW%spzwQB#z>pJjjSWmnt>&f>y9h}LxYvK8joVwhs#p$e^9;neXml|cLZJP}D#pP^$ zLeBX=<$RSRBXuzy`T9XhE0?tN>Y0?kyw%aW(=xX3NXMt1>cs2~y->cb!PP*+ovt4S zuJ`wecu_AJPP)6pH*TWZY~Z@~z@L}v>e}Vw=FpEOpv!1O7VbNNHL@uQVywy6htZ_C6Ss)QLCwnl(m|=NMRh^U@~(dHIf@ij$}uh zz7%QM60Q87clbDxiL|D34*!lOe()cE5A)3P{oKY)zMst{(+#zawW+#>WV$|OZ=1c} D7kk`W diff --git a/lib/pytz/zoneinfo/Europe/Uzhgorod b/lib/pytz/zoneinfo/Europe/Uzhgorod index 7032ab9b34f97640d1ef631dc4cc790abeeed606..00584c1fca222e39b8e11198c7e7df60cf4eeaf5 100644 GIT binary patch delta 170 zcmbO$u!C!Y_+%+&9!?hq1_oXrmfNT!z&Kfe$(fO7awn4q8v}!u0fW@!i%e27ZmuB= z42+CGMIeF^%mQ*ifN?S-v!o~=kOjgZ;0nYbw$f&OW(}sv|Jhs^c_&x0`*DE{l=JZo VVE`Gb4mK2rsUSPJfC_Ytxd5^16q5h| delta 834 zcmZ9}O-NK>6o>J9Wr!L~j=?Y@q>DC2la89yLTORAS~ycSS2HIw&98DA(@LBvyFm~U z5eIG%E~J7G7a>Jog1d-l5knh^7HwKZLmB==G1TBubuIFfuYUGBz?eGCDFmGCmRjiGYN#nixnBBnlD+#}Rcu7A1z?{30JJtOOkd-!|9HtX0c&HFf=KD!w*!C=?>1 z>9SqC*&ZU4BD&bE@MIz)VR`D(rT8Cu!9ei&4jlv!4m|UD80Pf-ZDzhd^&~&n=ka(r zJmcp0R?b;oyYb}%X-b5(`B7ZLR}*q&uufX4nk7VPU7hdr=G?m63O(2E*s|O%n$@0~r_!5|lz8Eo z#J|r--+om3*J5&Kw^{~Lp;j6E7}25mVo5Ar)ZxB#k%t935-!rwo_~6`!mDGKzv_6- zH=PLV$%KB;$&+7Xa^r@+LQCJjN5C`cG24iX57goHw3A;DZtG$fp>iH8J4A|fHt#I)TD zMfpHgq%2YwDU4J`N+Y$A;z)I*ysN2?EP$+lEP(?lJLFzigb%EOEQ73rEQG9tEQPFv zEQYLxEaz(0Ll$&3D3zH(VBGV%C;&Bs~@YDY%E80{aIUh9dmWaP07^n=C M`x`3Cu`HN%0CV5>q5uE@ diff --git a/lib/pytz/zoneinfo/Europe/Zaporozhye b/lib/pytz/zoneinfo/Europe/Zaporozhye index 2ccf8998b24f3493e68670c5d08c51ad759bf7f6..899fa88b63116211b2d2c8793772bbc6538106d3 100644 GIT binary patch delta 170 zcmZ1~aDZ!q_+&X|9!?hq1_oXrR@$f|z&Kfe$(fO7awn4q8v}!u0fXG+i%fEIZmuCf z1q_UgV9W@jVF1XPATG)WhKA(VYU9W2w`U;udGA^Du4p_~ z={OFDSJ52qi3dq>gUr2Ky1P)2Jy$Mh`@YM%H$R}+&3X0Pc4|jFqn*k1+PRq0uGkLg zdb>)yf7HnS$KN%#5S0TrtEA`AXXy>TN#C`y9PC?=LsOsh@YW~N-}73JR8Px5>zocQ zo!6l?szV>I>+r8}J^HGs$KLxoGMnqr{L3*peyLRpGg%oOuGSM5n`ErLMaBo?ax|mLU{UDPo7j^Q@3n_kir=|Nda;E%L&rUzrsks|^u6Rd-tAU0s?zV8$ zmA}rC@VvV#EW3%-=3jSRd*IK@b#>jclKHg4oV5>|D{3kNzGEL`BV;FJD`YQZGh{bp zJ7hnr*$~;$YPLl7L^efsMYC;SFAU5BMn;B4#zqE5Mn{H6#zz7m5s(m869Wl?L_xyf z$ZU|a7XtBsNJuCo77`4JhJ-`nApwzyNJy)Ri3GKps7P2WZ7_AYP#CFf8OEkNG8&j_8op5Tlj4@kQ4+N0m2}_0mSSRXK5+}O#tyhrhsXn eNgx_(8Vk@gwuz_Z(2WD~85p?2gF|!;jky5#{V0*C2xKoo4qKt)^fnh@f0|P|03_DkNaEPHH7Xbb`67&E7 diff --git a/lib/pytz/zoneinfo/Pacific/Easter b/lib/pytz/zoneinfo/Pacific/Easter index 4a3cf389c390148b4293a85c15f1cc9e11f84abc..1f7bae5373b932a230b0922e7a76f373bb70596b 100644 GIT binary patch delta 37 ncmbR1HrH*#L`L>w>;`@TO$Rp5V4Tmw4dgHY0a(C^?Y0a6{(cO$ delta 37 ncmbR1HrH*#L`L@Mk2d&ClyTTRgK<6!H;}^s1YiLtw%alQ9U2Y9 diff --git a/lib/pytz/zoneinfo/Turkey b/lib/pytz/zoneinfo/Turkey index a7c16e76d1743ccdf5f8b7e6f8ef761e23456cb1..864099556bc9875b7e9258af6c3b221d84c68eae 100644 GIT binary patch delta 25 ecmZ1|x=?fjBNKD~-3gmnnD()P8AsXgFaZF0fC={i delta 25 dcmZ1|x=?fjBNKC9kHBUYrhTkn#!>b=OaNz~2vYz6 diff --git a/lib/pytz/zoneinfo/W-SU b/lib/pytz/zoneinfo/W-SU index cf001a555feac1deb3f67ed9a6c0fb5ebfce8c96..6068f8b9e584385eb1096c4f9603da74aa3e4095 100644 GIT binary patch delta 72 zcmdlaxPyCwGNaE%6${46229?JJd-yv`EW4sGB8*;FbYnN=1`lg&1}x-yE&P;fN63y ZyALDpAJjiSbkzCBl!3jJTziw2 z>mTc7Fdu7^q1UZ?W3E!N%O~~bz&?@thjlnvp||>f>+M>jBMl$)PU$Bd4gZo+eWhb1 z?`7=W6CMBhQYKdBb#gN&Q%lP-{cKid#^=OY>=U=kG`cwx_{S}D^CliJL7(qf#8>S8 zF==!6c}Ia1I6m)C1gV0QLFyodkV;4?q!v=l>QzI^S-pBlL8Ky561|#^eUOw7vLb1b zyhvgsGm;v~jU-31Bk8SPeq;h<24o5x%sVmrU=lu<1(^n!2bl<&37HC+3z-a=4VljB z&4)~A^=3q-#EBYjPabTF?22rQ?2C5exBKI6slV{Qx7^ -# @(#)iso3166.tab 8.6 +# @(#)iso3166.tab 8.11 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # ISO 3166 alpha-2 country codes @@ -21,6 +21,9 @@ # # Lines beginning with `#' are comments. # +# From Arthur David Olson (2011-08-17): +# Resynchronized today with the ISO 3166 site (adding SS for South Sudan). +# #country- #code country name AD Andorra @@ -30,7 +33,6 @@ AG Antigua & Barbuda AI Anguilla AL Albania AM Armenia -AN Netherlands Antilles AO Angola AQ Antarctica AR Argentina @@ -53,6 +55,7 @@ BL St Barthelemy BM Bermuda BN Brunei BO Bolivia +BQ Bonaire Sint Eustatius & Saba BR Brazil BS Bahamas BT Bhutan @@ -75,6 +78,7 @@ CO Colombia CR Costa Rica CU Cuba CV Cape Verde +CW Curacao CX Christmas Island CY Cyprus CZ Czech Republic @@ -229,8 +233,10 @@ SM San Marino SN Senegal SO Somalia SR Suriname +SS South Sudan ST Sao Tome & Principe SV El Salvador +SX Sint Maarten SY Syria SZ Swaziland TC Turks & Caicos Is diff --git a/lib/pytz/zoneinfo/zone.tab b/lib/pytz/zoneinfo/zone.tab index 03a93a43585c..f197b948dd97 100644 --- a/lib/pytz/zoneinfo/zone.tab +++ b/lib/pytz/zoneinfo/zone.tab @@ -1,5 +1,5 @@ # Date: Thu, 13 Oct 2011 13:44:50 -0600 Subject: [PATCH 201/214] update Basemap URL to point to github instead of sourceforge --- doc/_templates/indexsidebar.html | 2 +- doc/mpl_toolkits/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index 37a9f2e3bf15..c6644ae94752 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -43,7 +43,7 @@

Toolkits

toolkits
-# @(#)zone.tab	8.41
+# @(#)zone.tab	8.49
 # This file is in the public domain, so clarified as of
 # 2009-05-17 by Arthur David Olson.
 #
@@ -32,7 +32,6 @@ AG	+1703-06148	America/Antigua
 AI	+1812-06304	America/Anguilla
 AL	+4120+01950	Europe/Tirane
 AM	+4011+04430	Asia/Yerevan
-AN	+1211-06900	America/Curacao
 AO	-0848+01314	Africa/Luanda
 AQ	-7750+16636	Antarctica/McMurdo	McMurdo Station, Ross Island
 AQ	-9000+00000	Antarctica/South_Pole	Amundsen-Scott Station, South Pole
@@ -87,6 +86,7 @@ BL	+1753-06251	America/St_Barthelemy
 BM	+3217-06446	Atlantic/Bermuda
 BN	+0456+11455	Asia/Brunei
 BO	-1630-06809	America/La_Paz
+BQ	+120903-0681636	America/Kralendijk
 BR	-0351-03225	America/Noronha	Atlantic islands
 BR	-0127-04829	America/Belem	Amapa, E Para
 BR	-0343-03830	America/Fortaleza	NE Brazil (MA, PI, CE, RN, PB)
@@ -120,7 +120,7 @@ CA	+4901-08816	America/Nipigon	Eastern Time - Ontario & Quebec - places that did
 CA	+4823-08915	America/Thunder_Bay	Eastern Time - Thunder Bay, Ontario
 CA	+6344-06828	America/Iqaluit	Eastern Time - east Nunavut - most locations
 CA	+6608-06544	America/Pangnirtung	Eastern Time - Pangnirtung, Nunavut
-CA	+744144-0944945	America/Resolute	Eastern Standard Time - Resolute, Nunavut
+CA	+744144-0944945	America/Resolute	Central Standard Time - Resolute, Nunavut
 CA	+484531-0913718	America/Atikokan	Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut
 CA	+624900-0920459	America/Rankin_Inlet	Central Time - central Nunavut
 CA	+4953-09709	America/Winnipeg	Central Time - Manitoba & west Ontario
@@ -155,6 +155,7 @@ CO	+0436-07405	America/Bogota
 CR	+0956-08405	America/Costa_Rica
 CU	+2308-08222	America/Havana
 CV	+1455-02331	Atlantic/Cape_Verde
+CW	+1211-06900	America/Curacao
 CX	-1025+10543	Indian/Christmas
 CY	+3510+03322	Asia/Nicosia
 CZ	+5005+01426	Europe/Prague
@@ -318,7 +319,8 @@ PL	+5215+02100	Europe/Warsaw
 PM	+4703-05620	America/Miquelon
 PN	-2504-13005	Pacific/Pitcairn
 PR	+182806-0660622	America/Puerto_Rico
-PS	+3130+03428	Asia/Gaza
+PS	+3130+03428	Asia/Gaza	Gaza Strip
+PS	+313200+0350542	Asia/Hebron	West Bank
 PT	+3843-00908	Europe/Lisbon	mainland
 PT	+3238-01654	Atlantic/Madeira	Madeira Islands
 PT	+3744-02540	Atlantic/Azores	Azores
@@ -360,8 +362,10 @@ SM	+4355+01228	Europe/San_Marino
 SN	+1440-01726	Africa/Dakar
 SO	+0204+04522	Africa/Mogadishu
 SR	+0550-05510	America/Paramaribo
+SS	+0451+03136	Africa/Juba
 ST	+0020+00644	Africa/Sao_Tome
 SV	+1342-08912	America/El_Salvador
+SX	+180305-0630250	America/Lower_Princes
 SY	+3330+03618	Asia/Damascus
 SZ	-2618+03106	Africa/Mbabane
 TC	+2128-07108	America/Grand_Turk

From ffa5c08f10719cd53230a7b74d176ff21e6b3ab1 Mon Sep 17 00:00:00 2001
From: Jeff Whitaker 

There are several matplotlib add-on , including the projection and mapping toolkit -, 3d plotting with , 3d plotting with , axes and axis helpers in and more.

basemapbasemapmplot3daxes_grid diff --git a/doc/mpl_toolkits/index.rst b/doc/mpl_toolkits/index.rst index a09ab7e2923e..fb64b5e42485 100644 --- a/doc/mpl_toolkits/index.rst +++ b/doc/mpl_toolkits/index.rst @@ -19,7 +19,7 @@ Basemap ======= Plots data on map projections, with continental and political -boundaries, see `basemap
`_ +boundaries, see `basemap `_ docs. .. _toolkit_gtk: From 9aa0bc6e92795efb37c0a2e16f238b1bad513484 Mon Sep 17 00:00:00 2001 From: jdh2358 Date: Thu, 13 Oct 2011 17:55:06 -0500 Subject: [PATCH 202/214] fix index sidebar --- doc/_templates/indexsidebar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/_templates/indexsidebar.html b/doc/_templates/indexsidebar.html index c6644ae94752..673a6d36892e 100644 --- a/doc/_templates/indexsidebar.html +++ b/doc/_templates/indexsidebar.html @@ -41,7 +41,7 @@

Videos

Toolkits

There are several matplotlib add-on , including the projection +pathto('mpl_toolkits/index') }}">toolkits, including the projection and mapping toolkit , 3d plotting with , axes and axis helpers in

toolkitsbasemapmplot3d #include +#include #include #include #include "pprdrv.h" From 2438af2bae0a9e723d780da9d94e5fad41f7a46b Mon Sep 17 00:00:00 2001 From: John Hunter Date: Sat, 15 Oct 2011 11:26:13 -0500 Subject: [PATCH 204/214] support animated property on figure elements --- lib/matplotlib/figure.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 5cef5b222759..50607f5ccc1e 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -827,13 +827,13 @@ def draw(self, renderer): dsu = [] for a in self.patches: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) for a in self.lines: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) for a in self.artists: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) # override the renderer default if self.suppressComposite # is not None @@ -844,7 +844,7 @@ def draw(self, renderer): if len(self.images)<=1 or not_composite or \ not allequal([im.origin for im in self.images]): for a in self.images: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) else: # make a composite image blending alpha # list of (_image.Image, ox, oy) @@ -866,21 +866,22 @@ def draw_composite(): renderer.draw_image(gc, l, b, im) gc.restore() - dsu.append((self.images[0].get_zorder(), draw_composite, [])) + dsu.append((self.images[0].get_zorder(), self.images[0], draw_composite, [])) # render the axes for a in self.axes: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) # render the figure text for a in self.texts: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) for a in self.legends: - dsu.append( (a.get_zorder(), a.draw, [renderer])) + dsu.append( (a.get_zorder(), a, a.draw, [renderer])) + dsu = [row for row in dsu if not row[1].get_animated()] dsu.sort(key=itemgetter(0)) - for zorder, func, args in dsu: + for zorder, a, func, args in dsu: func(*args) renderer.close_group('figure') From 2154b32c72226783258272f4f91677ae4e36d5bd Mon Sep 17 00:00:00 2001 From: Ian Thomas Date: Tue, 18 Oct 2011 07:48:11 -0500 Subject: [PATCH 205/214] fix triangulation typo --- lib/matplotlib/tri/triangulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tri/triangulation.py b/lib/matplotlib/tri/triangulation.py index c3062d301684..9ba82ea2acb4 100644 --- a/lib/matplotlib/tri/triangulation.py +++ b/lib/matplotlib/tri/triangulation.py @@ -171,7 +171,7 @@ def get_from_args_and_kwargs(*args, **kwargs): @property def neighbors(self): if self._neighbors is None: - self._neighbors = self._get_cpp_triangulation().get_neighbors() + self._neighbors = self.get_cpp_triangulation().get_neighbors() return self._neighbors def set_mask(self, mask): From 93e4d19884f32493fc90b226b0ad059f0c829ccd Mon Sep 17 00:00:00 2001 From: Christoph Gohlke Date: Tue, 18 Oct 2011 07:56:36 -0500 Subject: [PATCH 206/214] windows x64 support in _tkagg.so --- src/_tkagg.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 925c2b585c34..854b40bdd20f 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -34,6 +34,12 @@ extern "C" #endif } +#if defined(_MSC_VER) +# define SIZE_T_FORMAT "%Iu" +#else +# define SIZE_T_FORMAT "%zu" +#endif + typedef struct @@ -53,7 +59,7 @@ PyAggImagePhoto(ClientData clientdata, Tcl_Interp* interp, // vars for blitting PyObject* bboxo; - unsigned long aggl, bboxl; + size_t aggl, bboxl; bool has_bbox; agg::int8u *destbuffer; double l, b, r, t; @@ -83,7 +89,7 @@ PyAggImagePhoto(ClientData clientdata, Tcl_Interp* interp, return TCL_ERROR; } /* get array (or object that can be converted to array) pointer */ - if (sscanf(argv[2], "%lu", &aggl) != 1) + if (sscanf(argv[2], SIZE_T_FORMAT, &aggl) != 1) { Tcl_AppendResult(interp, "error casting pointer", (char *) NULL); return TCL_ERROR; @@ -109,7 +115,7 @@ PyAggImagePhoto(ClientData clientdata, Tcl_Interp* interp, } /* check for bbox/blitting */ - if (sscanf(argv[4], "%lu", &bboxl) != 1) + if (sscanf(argv[4], SIZE_T_FORMAT, &bboxl) != 1) { Tcl_AppendResult(interp, "error casting pointer", (char *) NULL); return TCL_ERROR; From fc30d9246e69c608f77c734acc0d244c58a24a9a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 18 Oct 2011 15:39:41 -0400 Subject: [PATCH 207/214] Fix inclusion of source code in the documentation build. Closes #520. --- doc/sphinxext/gen_rst.py | 24 +++++++++++----------- lib/matplotlib/sphinxext/plot_directive.py | 11 ++++++---- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/doc/sphinxext/gen_rst.py b/doc/sphinxext/gen_rst.py index 2502076c9f93..1bf72bba8ed6 100644 --- a/doc/sphinxext/gen_rst.py +++ b/doc/sphinxext/gen_rst.py @@ -113,6 +113,18 @@ def generate_example_rst(app): fhsubdirIndex.write(' %s <%s>\n'%(os.path.basename(basename),rstfile)) + do_plot = (subdir in ('api', + 'pylab_examples', + 'units', + 'mplot3d', + 'axes_grid', + ) and + not noplot_regex.search(contents)) + if not do_plot: + fhstatic = file(outputfile, 'w') + fhstatic.write(contents) + fhstatic.close() + if not out_of_date(fullpath, outrstfile): continue @@ -121,25 +133,13 @@ def generate_example_rst(app): title = '%s example code: %s'%(subdir, fname) #title = ' %s example code: %s'%(thumbfile, subdir, fname) - fh.write(title + '\n') fh.write('='*len(title) + '\n\n') - do_plot = (subdir in ('api', - 'pylab_examples', - 'units', - 'mplot3d', - 'axes_grid', - ) and - not noplot_regex.search(contents)) - if do_plot: fh.write("\n\n.. plot:: %s\n\n::\n\n" % fullpath) else: fh.write("[`source code <%s>`_]\n\n::\n\n" % fname) - fhstatic = file(outputfile, 'w') - fhstatic.write(contents) - fhstatic.close() # indent the contents contents = '\n'.join([' %s'%row.rstrip() for row in contents.split('\n')]) diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index f9ca13630114..5d7b2c524b72 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -764,10 +764,13 @@ def run(arguments, content, options, state_machine, state, lineno): shutil.copyfile(fn, destimg) # copy script (if necessary) + target_name = os.path.join(dest_dir, output_base + source_ext) + f = open(target_name, 'w') if source_file_name == rst_file: - target_name = os.path.join(dest_dir, output_base + source_ext) - f = open(target_name, 'w') - f.write(unescape_doctest(code)) - f.close() + code_escaped = unescape_doctest(code) + else: + code_escaped = code + f.write(code_escaped) + f.close() return errors From f2341b535ccd019c710df671feb7cd8ad2646ff6 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 21 Oct 2011 14:12:54 -0400 Subject: [PATCH 208/214] Display information about the version of PySide installed from setup.py --- setup.py | 3 ++- setupext.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2f138218881d..649e8e57b464 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ build_ttconv, print_line, print_status, print_message, \ print_raw, check_for_freetype, check_for_libpng, check_for_gtk, \ check_for_tk, check_for_macosx, check_for_numpy, \ - check_for_qt, check_for_qt4, check_for_cairo, \ + check_for_qt, check_for_qt4, check_for_pyside, check_for_cairo, \ check_provide_pytz, check_provide_dateutil,\ check_for_dvipng, check_for_ghostscript, check_for_latex, \ check_for_pdftops, check_for_datetime, options, build_png, build_tri @@ -173,6 +173,7 @@ def chop_package(fname): # These are informational only. We don't build any extensions for them. check_for_qt() check_for_qt4() +check_for_pyside() check_for_cairo() print_raw("") diff --git a/setupext.py b/setupext.py index 962cedc3d752..9e032cab7d12 100644 --- a/setupext.py +++ b/setupext.py @@ -417,6 +417,18 @@ def check_for_qt4(): pyqtconfig.Configuration().pyqt_version_str)) return True +def check_for_pyside(): + try: + from PySide import __version__ + from PySide import QtCore + except ImportError: + print_status("PySide", "no") + return False + else: + print_status("PySide", "Qt: %s, PySide: %s" % + (QtCore.__version__, __version__)) + return True + def check_for_cairo(): try: import cairo From e406c05bd0c4ae9b0d6cc5aef5771740db0db240 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 24 Oct 2011 11:00:18 -0400 Subject: [PATCH 209/214] Make "set_alpha()" work on images. Now, alpha blending is handled in the backends. Tested and works on Agg, Pdf and Svg. (Ps does not support alpha). --- lib/matplotlib/backends/backend_svg.py | 4 ++++ lib/matplotlib/image.py | 14 +++++++++----- src/_backend_agg.cpp | 6 +++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index b6542eecba63..25891630841a 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -757,6 +757,10 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): im.flipud_out() attrib['xlink:href'] = filename + alpha = gc.get_alpha() + if alpha != 1.0: + attrib['opacity'] = str(alpha) + if transform is None: self.writer.element( 'image', diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 12711ec55370..9b7076795e72 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -199,7 +199,7 @@ def _get_unsampled_image(self, A, image_extents, viewlim): im.is_grayscale = False else: if self._rgbacache is None: - x = self.to_rgba(self._A, self._alpha, bytes=True) + x = self.to_rgba(self._A, bytes=True) self._rgbacache = x else: x = self._rgbacache @@ -345,6 +345,7 @@ def draw(self, renderer, *args, **kwargs): gc = renderer.new_gc() gc.set_clip_rectangle(self.axes.bbox.frozen()) gc.set_clip_path(self.get_clip_path()) + gc.set_alpha(self.get_alpha()) if self._check_unsampled_image(renderer): self._draw_unsampled_image(renderer, gc) @@ -722,7 +723,7 @@ def set_data(self, x, y, A): A.shape = A.shape[0:2] if len(A.shape) == 2: if A.dtype != np.uint8: - A = self.to_rgba(A, alpha=self._alpha, bytes=True) + A = self.to_rgba(A, bytes=True) self.is_grayscale = self.cmap.is_gray() else: A = np.repeat(A[:,:,np.newaxis], 4, 2) @@ -824,7 +825,7 @@ def make_image(self, magnification=1.0): width = width * magnification height = height * magnification if self._rgbacache is None: - A = self.to_rgba(self._A, alpha=self._alpha, bytes=True) + A = self.to_rgba(self._A, bytes=True) self._rgbacache = A if self._A.ndim == 2: self.is_grayscale = self.cmap.is_gray() @@ -851,6 +852,7 @@ def draw(self, renderer, *args, **kwargs): gc = renderer.new_gc() gc.set_clip_rectangle(self.axes.bbox.frozen()) gc.set_clip_path(self.get_clip_path()) + gc.set_alpha(self.get_alpha()) renderer.draw_image(gc, round(self.axes.bbox.xmin), round(self.axes.bbox.ymin), @@ -974,7 +976,7 @@ def make_image(self, magnification=1.0): if self._A is None: raise RuntimeError('You must first set the image array') - x = self.to_rgba(self._A, self._alpha, bytes=True) + x = self.to_rgba(self._A, bytes=True) self.magnification = magnification # if magnification is not one, we need to resize ismag = magnification!=1 @@ -1008,6 +1010,7 @@ def draw(self, renderer, *args, **kwargs): gc = renderer.new_gc() gc.set_clip_rectangle(self.figure.bbox) gc.set_clip_path(self.get_clip_path()) + gc.set_alpha(self.get_alpha()) renderer.draw_image(gc, round(self.ox), round(self.oy), im) gc.restore() @@ -1096,7 +1099,7 @@ def make_image(self, renderer, magnification=1.0): im.is_grayscale = False else: if self._rgbacache is None: - x = self.to_rgba(self._A, self._alpha, bytes=True) + x = self.to_rgba(self._A, bytes=True) self._rgbacache = x else: x = self._rgbacache @@ -1148,6 +1151,7 @@ def draw(self, renderer, *args, **kwargs): l, b, r, t = self.get_window_extent(renderer).extents gc = renderer.new_gc() self._set_gc_clip(gc) + gc.set_alpha(self.get_alpha()) #gc.set_clip_path(self.get_clip_path()) renderer.draw_image(gc, round(l), round(b), im) gc.restore() diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index 200fad33461a..f7a986fc2f95 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -988,6 +988,7 @@ RendererAgg::draw_image(const Py::Tuple& args) agg::trans_affine affine_trans; bool has_affine = false; double x, y, w, h; + double alpha; if (args.size() == 7) { @@ -1006,6 +1007,8 @@ RendererAgg::draw_image(const Py::Tuple& args) warnings from the compiler */ } + alpha = gc.alpha; + theRasterizer.reset_clipping(); rendererBase.reset_clipping(true); set_clipbox(gc.cliprect, theRasterizer); @@ -1097,7 +1100,8 @@ RendererAgg::draw_image(const Py::Tuple& args) else { set_clipbox(gc.cliprect, rendererBase); - rendererBase.blend_from(pixf, 0, (int)x, (int)(height - (y + image->rowsOut))); + rendererBase.blend_from( + pixf, 0, (int)x, (int)(height - (y + image->rowsOut)), alpha * 255); } rendererBase.reset_clipping(true); From 1dac36d829a8737741e1b223049042a4bc096070 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 21 Oct 2011 09:34:11 -0400 Subject: [PATCH 210/214] Tell Agg that we're giving it pre-multiplied image data --- src/_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_image.cpp b/src/_image.cpp index 3278b6c382b0..6bb202a8b320 100644 --- a/src/_image.cpp +++ b/src/_image.cpp @@ -33,7 +33,7 @@ #include "mplutils.h" -typedef agg::pixfmt_rgba32 pixfmt; +typedef agg::pixfmt_rgba32_pre pixfmt; typedef agg::renderer_base renderer_base; typedef agg::span_interpolator_linear<> interpolator_type; typedef agg::rasterizer_scanline_aa rasterizer; From c459dc5d07bba454b1ac5d97a6b21048e9f01a64 Mon Sep 17 00:00:00 2001 From: Paul Ivanov Date: Mon, 24 Oct 2011 23:02:43 -0700 Subject: [PATCH 211/214] added support for \operatorname (closes #553) I started with the version of the related code written by Freddie Witherden and committed to (the now abandoned?) mathtex spinoff project which didn't makes its way back to matplotlib. However, that code: http://code.google.com/p/mathtex/source/detail?r=75 allowed only to lower- and upper-case letters to be used inside of \operatorname. I have improved it to allow the usage of any simple character - including the insertion of spaces - such that $\operator{arg\,max}$ actually inserts a space between arg max --- CHANGELOG | 4 ++++ lib/matplotlib/mathtext.py | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 9f5c700bafaa..1369718afb92 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2011-10-25 added support for \operatorname to mathtext, + including the ability to insert spaces, such as + $\operatorname{arg\,max}$ - PI + 2011-08-18 Change api of Axes.get_tightbbox and add an optional keyword parameter *call_axes_locator*. - JJL diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index f9dd615d8e41..df849b491c17 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -2269,6 +2269,12 @@ def __init__(self): + (group | Error("Expected \overline{value}")) ).setParseAction(self.overline).setName("overline") + operatorname = Group( + Suppress(Literal(r"\operatorname")) + + ((start_group + ZeroOrMore(simple) + end_group) + | Error("Expected \operatorname{value}")) + ).setParseAction(self.operatorname).setName("operatorname") + placeable <<(function ^ (c_over_c | symbol) ^ accent @@ -2279,6 +2285,7 @@ def __init__(self): ^ genfrac ^ sqrt ^ overline + ^ operatorname ) simple <<(space @@ -2578,6 +2585,18 @@ def function(self, s, loc, toks): hlist.function_name = toks[0] return hlist + def operatorname(self, s, loc, toks): + self.push_state() + state = self.get_state() + state.font = 'rm' + # Change the font of Chars, but leave Kerns alone + for c in toks[0]: + if isinstance(c,Char): + c.font = 'rm' + c._update_metrics() + self.pop_state() + return Hlist(toks[0]) + def start_group(self, s, loc, toks): self.push_state() # Deal with LaTeX-style font tokens From bb9946260e44e3faa2611bf781e56609320bc0d8 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 25 Oct 2011 09:50:27 -0400 Subject: [PATCH 212/214] backend_qt4: avoid a crash at exit with PySide. Closes #551. --- lib/matplotlib/backends/backend_qt4.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index 8d4f0d424d6d..279a3c205af7 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -361,6 +361,8 @@ def show(self): self.window.show() def destroy( self, *args ): + # check for qApp first, as PySide deletes it in its atexit handler + if QtGui.QApplication.instance() is None: return if self.window._destroying: return self.window._destroying = True QtCore.QObject.disconnect( self.window, QtCore.SIGNAL( 'destroyed()' ), From 9fbeb22b0321969f524e9fdcd9a2b8f7e1e37f46 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 26 Oct 2011 11:00:09 -0400 Subject: [PATCH 213/214] Major overhaul of the mathtext parser to get better error messages out of it. Has the side benefit of being faster. --- lib/matplotlib/mathtext.py | 441 ++++++++--------- .../test_mathtext/mathtext_cm_66.pdf | Bin 0 -> 6727 bytes .../test_mathtext/mathtext_cm_66.png | Bin 0 -> 1359 bytes .../test_mathtext/mathtext_cm_66.svg | 203 ++++++++ .../test_mathtext/mathtext_cm_67.pdf | Bin 0 -> 13707 bytes .../test_mathtext/mathtext_cm_67.png | Bin 0 -> 3097 bytes .../test_mathtext/mathtext_cm_67.svg | 459 ++++++++++++++++++ .../test_mathtext/mathtext_stix_66.pdf | Bin 0 -> 6293 bytes .../test_mathtext/mathtext_stix_66.png | Bin 0 -> 1342 bytes .../test_mathtext/mathtext_stix_66.svg | 155 ++++++ .../test_mathtext/mathtext_stix_67.pdf | Bin 0 -> 10634 bytes .../test_mathtext/mathtext_stix_67.png | Bin 0 -> 2769 bytes .../test_mathtext/mathtext_stix_67.svg | 321 ++++++++++++ .../test_mathtext/mathtext_stixsans_66.pdf | Bin 0 -> 4482 bytes .../test_mathtext/mathtext_stixsans_66.png | Bin 0 -> 1310 bytes .../test_mathtext/mathtext_stixsans_66.svg | 117 +++++ .../test_mathtext/mathtext_stixsans_67.pdf | Bin 0 -> 10213 bytes .../test_mathtext/mathtext_stixsans_67.png | Bin 0 -> 2664 bytes .../test_mathtext/mathtext_stixsans_67.svg | 254 ++++++++++ lib/matplotlib/tests/test_mathtext.py | 39 +- 20 files changed, 1768 insertions(+), 221 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.pdf create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.png create mode 100644 lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.svg diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index df849b491c17..6b93032f4dba 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -33,7 +33,7 @@ from matplotlib.pyparsing import Combine, Group, Optional, Forward, \ Literal, OneOrMore, ZeroOrMore, ParseException, Empty, \ ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ - FollowedBy, Regex, ParserElement + FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException # Enable packrat parsing ParserElement.enablePackrat() @@ -2046,7 +2046,7 @@ def Error(msg): Helper class to raise parser errors. """ def raise_error(s, loc, toks): - raise ParseFatalException(msg + "\n" + s) + raise ParseFatalException(s, loc, msg) empty = Empty() empty.setParseAction(raise_error) @@ -2123,219 +2123,209 @@ class Parser(object): liminf sin cos exp limsup sinh cosh gcd ln sup cot hom log tan coth inf max tanh""".split()) - _ambiDelim = set(r""" + _ambi_delim = set(r""" | \| / \backslash \uparrow \downarrow \updownarrow \Uparrow \Downarrow \Updownarrow .""".split()) - _leftDelim = set(r"( [ { < \lfloor \langle \lceil".split()) + _left_delim = set(r"( [ { < \lfloor \langle \lceil".split()) - _rightDelim = set(r") ] } > \rfloor \rangle \rceil".split()) + _right_delim = set(r") ] } > \rfloor \rangle \rceil".split()) def __init__(self): # All forward declarations are here - font = Forward().setParseAction(self.font).setName("font") - latexfont = Forward() - subsuper = Forward().setParseAction(self.subsuperscript).setName("subsuper") - placeable = Forward().setName("placeable") - simple = Forward().setName("simple") - autoDelim = Forward().setParseAction(self.auto_sized_delimiter) - self._expression = Forward().setParseAction(self.finish).setName("finish") - - float = Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") - - lbrace = Literal('{').suppress() - rbrace = Literal('}').suppress() - start_group = (Optional(latexfont) - lbrace) - start_group.setParseAction(self.start_group) - end_group = rbrace.copy() - end_group.setParseAction(self.end_group) - - bslash = Literal('\\') - - accent = oneOf(self._accent_map.keys() + - list(self._wide_accents)) - - function = oneOf(list(self._function_names)) - - fontname = oneOf(list(self._fontnames)) - latex2efont = oneOf(['math' + x for x in self._fontnames]) - - space =(FollowedBy(bslash) - + oneOf([r'\ ', - r'\/', - r'\,', - r'\;', - r'\quad', - r'\qquad', - r'\!']) - ).setParseAction(self.space).setName('space') - - customspace =(Literal(r'\hspace') - - (( lbrace - - float - - rbrace - ) | Error(r"Expected \hspace{n}")) - ).setParseAction(self.customspace).setName('customspace') - - unicode_range = u"\U00000080-\U0001ffff" - symbol =(Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" % unicode_range) - | (Combine( - bslash - + oneOf(tex2uni.keys()) - ) + FollowedBy(Regex("[^a-zA-Z]"))) - ).setParseAction(self.symbol).leaveWhitespace() - - c_over_c =(Suppress(bslash) - + oneOf(self._char_over_chars.keys()) - ).setParseAction(self.char_over_chars) - - accent = Group( - Suppress(bslash) - + accent - - placeable - ).setParseAction(self.accent).setName("accent") - - function =(Suppress(bslash) - + function - ).setParseAction(self.function).setName("function") - - group = Group( - start_group - + ZeroOrMore( - autoDelim - ^ simple) - - end_group - ).setParseAction(self.group).setName("group") - - font <<(Suppress(bslash) - + fontname) - - latexfont <<(Suppress(bslash) - + latex2efont) - - frac = Group( - Suppress(Literal(r"\frac")) - + ((group + group) - | Error(r"Expected \frac{num}{den}")) - ).setParseAction(self.frac).setName("frac") - - stackrel = Group( - Suppress(Literal(r"\stackrel")) - + ((group + group) - | Error(r"Expected \stackrel{num}{den}")) - ).setParseAction(self.stackrel).setName("stackrel") - - - binom = Group( - Suppress(Literal(r"\binom")) - + ((group + group) - | Error(r"Expected \binom{num}{den}")) - ).setParseAction(self.binom).setName("binom") - - ambiDelim = oneOf(list(self._ambiDelim)) - leftDelim = oneOf(list(self._leftDelim)) - rightDelim = oneOf(list(self._rightDelim)) - rightDelimSafe = oneOf(list(self._rightDelim - set(['}']))) - genfrac = Group( - Suppress(Literal(r"\genfrac")) - + ((Suppress(Literal('{')) + - oneOf(list(self._ambiDelim | self._leftDelim | set(['']))) + - Suppress(Literal('}')) + - Suppress(Literal('{')) + - oneOf(list(self._ambiDelim | - (self._rightDelim - set(['}'])) | - set(['', r'\}']))) + - Suppress(Literal('}')) + - Suppress(Literal('{')) + - Regex("[0-9]*(\.?[0-9]*)?") + - Suppress(Literal('}')) + - group + group + group) - | Error(r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) - ).setParseAction(self.genfrac).setName("genfrac") - - sqrt = Group( - Suppress(Literal(r"\sqrt")) - + Optional( - Suppress(Literal("[")) - - Regex("[0-9]+") - - Suppress(Literal("]")), - default = None - ) - + (group | Error("Expected \sqrt{value}")) - ).setParseAction(self.sqrt).setName("sqrt") - - overline = Group( - Suppress(Literal(r"\overline")) - + (group | Error("Expected \overline{value}")) - ).setParseAction(self.overline).setName("overline") - - operatorname = Group( - Suppress(Literal(r"\operatorname")) - + ((start_group + ZeroOrMore(simple) + end_group) - | Error("Expected \operatorname{value}")) - ).setParseAction(self.operatorname).setName("operatorname") - - placeable <<(function - ^ (c_over_c | symbol) - ^ accent - ^ group - ^ frac - ^ stackrel - ^ binom - ^ genfrac - ^ sqrt - ^ overline - ^ operatorname - ) - - simple <<(space - | customspace - | font - | subsuper - ) - - subsuperop = oneOf(["_", "^"]) - - subsuper << Group( - ( Optional(placeable) - + OneOrMore( - subsuperop + accent = Forward() + ambi_delim = Forward() + auto_delim = Forward() + binom = Forward() + bslash = Forward() + c_over_c = Forward() + customspace = Forward() + end_group = Forward() + float_literal = Forward() + font = Forward() + frac = Forward() + function = Forward() + genfrac = Forward() + group = Forward() + int_literal = Forward() + latexfont = Forward() + lbracket = Forward() + left_delim = Forward() + lbrace = Forward() + main = Forward() + math = Forward() + math_string = Forward() + non_math = Forward() + operatorname = Forward() + overline = Forward() + placeable = Forward() + rbrace = Forward() + rbracket = Forward() + required_group = Forward() + right_delim = Forward() + right_delim_safe = Forward() + simple = Forward() + simple_group = Forward() + single_symbol = Forward() + space = Forward() + sqrt = Forward() + stackrel = Forward() + start_group = Forward() + subsuper = Forward() + subsuperop = Forward() + symbol = Forward() + symbol_name = Forward() + token = Forward() + unknown_symbol = Forward() + + # Set names on everything -- very useful for debugging + for key, val in locals().items(): + if key != 'self': + val.setName(key) + + float_literal << Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") + int_literal << Regex("[-+]?[0-9]+") + + lbrace << Literal('{').suppress() + rbrace << Literal('}').suppress() + lbracket << Literal('[').suppress() + rbracket << Literal(']').suppress() + bslash << Literal('\\') + + space << oneOf(self._space_widths.keys()) + customspace << (Suppress(Literal(r'\hspace')) + - ((lbrace + float_literal + rbrace) + | Error(r"Expected \hspace{n}"))) + + unicode_range = u"\U00000080-\U0001ffff" + single_symbol << Regex(UR"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" % + unicode_range) + symbol_name << (Combine(bslash + oneOf(tex2uni.keys())) + + FollowedBy(Regex("[^A-Za-z]").leaveWhitespace() | StringEnd())) + symbol << (single_symbol | symbol_name).leaveWhitespace() + + c_over_c << Suppress(bslash) + oneOf(self._char_over_chars.keys()) + + accent << Group( + Suppress(bslash) + + oneOf(self._accent_map.keys() + list(self._wide_accents)) - placeable - ) ) - | placeable - ) - - autoDelim <<(Suppress(Literal(r"\left")) - + ((leftDelim | ambiDelim) | Error("Expected a delimiter")) - + Group( - OneOrMore( - autoDelim - ^ simple)) - + Suppress(Literal(r"\right")) - + ((rightDelim | ambiDelim) | Error("Expected a delimiter")) - ) - - math = OneOrMore( - autoDelim - ^ simple - ).setParseAction(self.math).setName("math") - - math_delim = ~bslash + Literal('$') - - non_math = Regex(r"(?:(?:\\[$])|[^$])*" - ).setParseAction(self.non_math).setName("non_math").leaveWhitespace() - - self._expression << ( - non_math - + ZeroOrMore( - Suppress(math_delim) - + Optional(math) - + (Suppress(math_delim) - | Error("Expected end of math '$'")) - + non_math - ) - ) + StringEnd() + + function << Suppress(bslash) + oneOf(list(self._function_names)) + + start_group << Optional(latexfont) + lbrace + end_group << rbrace.copy() + simple_group << Group(lbrace + ZeroOrMore(token) + rbrace) + required_group<< Group(lbrace + OneOrMore(token) + rbrace) + group << Group(start_group + ZeroOrMore(token) + end_group) + + font << Suppress(bslash) + oneOf(list(self._fontnames)) + latexfont << Suppress(bslash) + oneOf(['math' + x for x in self._fontnames]) + + frac << Group( + Suppress(Literal(r"\frac")) + - ((required_group + required_group) | Error(r"Expected \frac{num}{den}")) + ) + + stackrel << Group( + Suppress(Literal(r"\stackrel")) + - ((required_group + required_group) | Error(r"Expected \stackrel{num}{den}")) + ) + + binom << Group( + Suppress(Literal(r"\binom")) + - ((required_group + required_group) | Error(r"Expected \binom{num}{den}")) + ) + + ambi_delim << oneOf(list(self._ambi_delim)) + left_delim << oneOf(list(self._left_delim)) + right_delim << oneOf(list(self._right_delim)) + right_delim_safe << oneOf(list(self._right_delim - set(['}'])) + [r'\}']) + + genfrac << Group( + Suppress(Literal(r"\genfrac")) + - (((lbrace + Optional(ambi_delim | left_delim, default='') + rbrace) + + (lbrace + Optional(ambi_delim | right_delim_safe, default='') + rbrace) + + (lbrace + float_literal + rbrace) + + simple_group + required_group + required_group) + | Error(r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) + ) + + sqrt << Group( + Suppress(Literal(r"\sqrt")) + - ((Optional(lbracket + int_literal + rbracket, default=None) + + required_group) + | Error("Expected \sqrt{value}")) + ) + + overline << Group( + Suppress(Literal(r"\overline")) + - (required_group | Error("Expected \overline{value}")) + ) + + unknown_symbol<< Combine(bslash + Regex("[A-Za-z]*")) + + operatorname << Group( + Suppress(Literal(r"\operatorname")) + - ((lbrace + ZeroOrMore(simple | unknown_symbol) + rbrace) + | Error("Expected \operatorname{value}")) + ) + + placeable << ( symbol # Must be first + | c_over_c + | function + | accent + | group + | frac + | stackrel + | binom + | genfrac + | sqrt + | overline + | operatorname + ) + + simple << ( space + | customspace + | font + | subsuper + ) + + subsuperop << oneOf(["_", "^"]) + + subsuper << Group( + (Optional(placeable) + OneOrMore(subsuperop - placeable)) + | placeable + ) + + token << ( simple + | auto_delim + | unknown_symbol # Must be last + ) + + auto_delim << (Suppress(Literal(r"\left")) + - ((left_delim | ambi_delim) | Error("Expected a delimiter")) + + Group(ZeroOrMore(simple | auto_delim)) + + Suppress(Literal(r"\right")) + - ((right_delim | ambi_delim) | Error("Expected a delimiter")) + ) + + math << OneOrMore(token) + + math_string << QuotedString('$', '\\', unquoteResults=False) + + non_math << Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace() + + main << (non_math + ZeroOrMore(math_string + non_math)) + StringEnd() + + # Set actions + for key, val in locals().items(): + if hasattr(self, key): + val.setParseAction(getattr(self, key)) + + self._expression = main + self._math_expression = math self.clear() @@ -2357,7 +2347,7 @@ def parse(self, s, fonts_object, fontsize, dpi): self._state_stack = [self.State(fonts_object, 'default', 'rm', fontsize, dpi)] try: self._expression.parseString(s) - except ParseException, err: + except ParseBaseException, err: raise ValueError("\n".join([ "", err.line, @@ -2418,11 +2408,15 @@ def push_state(self): """ self._state_stack.append(self.get_state().copy()) - def finish(self, s, loc, toks): + def main(self, s, loc, toks): #~ print "finish", toks self._expr = Hlist(toks) return [self._expr] + def math_string(self, s, loc, toks): + # print "math_string", toks[0][1:-1] + return self._math_expression.parseString(toks[0][1:-1]) + def math(self, s, loc, toks): #~ print "math", toks hlist = Hlist(toks) @@ -2465,7 +2459,7 @@ def space(self, s, loc, toks): return [box] def customspace(self, s, loc, toks): - return [self._make_space(float(toks[1]))] + return [self._make_space(float(toks[0]))] def symbol(self, s, loc, toks): # print "symbol", toks @@ -2475,7 +2469,7 @@ def symbol(self, s, loc, toks): try: char = Char(c, self.get_state()) except ValueError: - raise ParseFatalException("Unknown symbol: %s" % c) + raise ParseFatalException(s, loc, "Unknown symbol: %s" % c) if c in self._spaced_symbols: return [Hlist( [self._make_space(0.2), @@ -2488,6 +2482,11 @@ def symbol(self, s, loc, toks): do_kern = False)] return [char] + def unknown_symbol(self, s, loc, toks): + # print "symbol", toks + c = toks[0] + raise ParseFatalException(s, loc, "Unknown symbol: %s" % c) + _char_over_chars = { # The first 2 entires in the tuple are (font, char, sizescale) for # the two symbols under and over. The third element is the space @@ -2495,7 +2494,7 @@ def symbol(self, s, loc, toks): r'AA' : ( ('rm', 'A', 1.0), (None, '\circ', 0.5), 0.0), } - def char_over_chars(self, s, loc, toks): + def c_over_c(self, s, loc, toks): sym = toks[0] state = self.get_state() thickness = state.font_output.get_underline_thickness( @@ -2591,7 +2590,7 @@ def operatorname(self, s, loc, toks): state.font = 'rm' # Change the font of Chars, but leave Kerns alone for c in toks[0]: - if isinstance(c,Char): + if isinstance(c, Char): c.font = 'rm' c._update_metrics() self.pop_state() @@ -2607,6 +2606,7 @@ def start_group(self, s, loc, toks): def group(self, s, loc, toks): grp = Hlist(toks[0]) return [grp] + required_group = simple_group = group def end_group(self, s, loc, toks): self.pop_state() @@ -2635,9 +2635,9 @@ def is_slanted(self, nucleus): return nucleus.is_slanted() return False - def subsuperscript(self, s, loc, toks): + def subsuper(self, s, loc, toks): assert(len(toks)==1) - # print 'subsuperscript', toks + # print 'subsuper', toks nucleus = None sub = None @@ -2900,8 +2900,12 @@ def overline(self, s, loc, toks): def _auto_sized_delimiter(self, front, middle, back): state = self.get_state() - height = max([x.height for x in middle]) - depth = max([x.depth for x in middle]) + if len(middle): + height = max([x.height for x in middle]) + depth = max([x.depth for x in middle]) + else: + height = 0 + depth = 0 parts = [] # \left. and \right. aren't supposed to produce any symbols if front != '.': @@ -2912,9 +2916,8 @@ def _auto_sized_delimiter(self, front, middle, back): hlist = Hlist(parts) return hlist - - def auto_sized_delimiter(self, s, loc, toks): - #~ print "auto_sized_delimiter", toks + def auto_delim(self, s, loc, toks): + #~ print "auto_delim", toks front, middle, back = toks return self._auto_sized_delimiter(front, middle.asList(), back) diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.pdf new file mode 100644 index 0000000000000000000000000000000000000000..49f5ce3ebeac17df2e1d9371385fffd2b4c22b2a GIT binary patch literal 6727 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 Jxp=#>{tZ&-B31wZ literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.png new file mode 100644 index 0000000000000000000000000000000000000000..32f24662bc7f1c0d2183412af0c4c4eca597968c GIT binary patch literal 1359 zcmd5+jWgS49RIOSQR=MQN-Wbmv>n5g2p5_TJ<>#VUY14zAvB8^L=pbYN)j( z%o2hiYfM;3Bm|jS0~>2@21Xt0_c1UX%Lu|mn*+%+|E>_MEz-gW84zT1<48@Op&M_5 zGg?f@*U>q=^;g(J8P#z}TPzu5g`F%3<_-?~z)Fjx+~ME&+yeJx3je%=t;08#mxm)u zIozP}>sBsLDA#d+)m7Bl7d#pF!|4*9^(-_k#|GRCn9vCKqJxbP)PHz<9D+W!wT3R){`ZDGV$ue(s-ez_7dO;BE32zl7!1az?y=E?z4vc| zXJ%$zDiq}n4Gp-O08#svc78}DW}u8lBSDm&G%IFQed6|Q^t2>zmqXv)sBdm|%~%>6 z(J0zf8mgjJGx; zbQ>ymls|MpZoVG4?}J3zjI{RG-e@#o)xDdOkk#Fp{&_oTzLdWoIoqSMD4z$?xKgQ< zqV7hdrlwY)vVY(#fO~}AoI6YM+S-kc4IIzUE2;s9;e6(oc4mkTZ&CHs*Sq|D5`Kjf zjmIw=^cqq2yZEgQb(JthaqtF{kG}m!KagwaWA7!IhX+OL7>-_}AitG#gg_xE3_38a@5oH)G%U}=iJ@RMNb8qVc;4JhP;D){{+ch zW77J{L?c0*m+O%r=G~c>E>1Q@CqG1(DACnOh7_f@-&? zzUo|??L&dRa59+;iuc&-rj#!fBIsLdBctV>-sua&s_slTBy|=S9v&V`B%c> zyvee$YE*XmKX1pKF-#^CAXI+hv+8F^w$U}zw;IhT2;3EAF(Sv?%?}kvZ0htC0&vV;@&Et; literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg new file mode 100644 index 000000000000..7b61d5effb40 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg @@ -0,0 +1,203 @@ + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8f931ae304c95e57f43867bf39fb6381a39a7381 GIT binary patch literal 13707 zcmd5@3p|v~_kSx&8+yA*30ol*_I|6}C6c=csTS+jy0liI=t3cq2yYUJD9SC7bfJ`r zN~NT7Dak#Bs8Iiz$F5zJ-|u}tzyIg=Tc7bf&v|CfoH;Xd&YADbBWt9kt%y@1qGT_; zL1$b=;m}yLyR8dq%^Ebu%*TU)#%R*nbf&u_8e>FvWO$ + + + + + + + + + + + + + + + + + + + + + + + + yF4_i- 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg new file mode 100644 index 000000000000..f12093272eff --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg @@ -0,0 +1,459 @@ + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2c8fc05e1fa42791f30b1e39fd149b9de89d1ab6 GIT binary patch literal 6293 zcmd5>d011&7T2esji_~BigHDKqAa;L_uecP`9wCsT4YgCifu@4LNp|pTq+{vxzvTC zRK$u4TC_#lhbv-hwc>_b>r%xH6-6zI(pF2W)`jxsOmayKX#3jt#|z(lGjrz5nRCv} zJ?A&Wps_(AK9nyb8np2WQM^k;5hP(um?HA?Bg8Q?k~u;gsN|J;qm~elRcbjiAwdjL zgulOtGpK=4ZZ{z|B4G-r;t3h%K@)hMGZ_dLx+3vdlTj7T@kAUF6%>NRbE!Nb4ogB} zM_TJZYaK?!6XM`hJ~WzF@*Kff1Vkq))jETgkXpot7!5o@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Dqd8Hxf?IVre%V0~bI$Adu>kdXzEG=v} z1@8YdhD)R@xXWgBPME=oY9I8-->KI^wX^D}Uq9}FxiP7KX~|Yks{1&(yZQs4$Gf^t z>8hxSTX1dQuBeRALF^al^WE}_Z+x1U`Lw%i#{8;fvy{E&>FD8s7kmo(`c;N5&+V8S zx97wtGRe7>2cKG^U#~86jdp+Q*Ujg-#7#%bkA)aKv$OuW{@fzBx;v6;?Vc`45pngO zxy;N@o%49Jeu*SEhO8d_depkBef&zVPwcxRKKeT0wxlHT(8Zn?ckDTRW_V^duTMTp z8TO1X?^7|4nbvmilO*X-@@&SM{N8RoHa+NdCT{SUvJL(myP+h$)9nCtSyiPr_|<(W z;R$O}iq0H5x#Qc?OUoKR&NzI^OHJkxam))QoDlzB_I zJ-(ji`b)ouhKUCMx}NtxX!qWg+@#As+x1KCRV3tQ2lvTZHRZMUI$S+*p<%kAEHS5z zM*UtTxxl3``_AJ@`~1dB7wlQOXsw59fSc&n@6LSv@O8aa0M1d^!wzHR)xJF~qGeg34qA~K%KmSi@h73cDMPZ#M{ zWO@b3p9KY6h}kkPD_5- zw_I|qOIuOcW$Va3)BU`&H0!v#lQOmauKoDPZD;tucC@fT_CfAt-?~I1d2WN)NNQ;t zs(sy~9_iH@?|ssYQ&&Izw(;^PeN=ef=B;Kl;tKE5M^Y9g+)tgI>RvtDS@1MQ>SLZ{0xX;eb zPuC30yYYGXrQtcBl&$(9v?TDi83#ODv%%7(6IXq7_Sb&-o$E~}Jo{{Ttcfx_TCuqF zXq!xBMK@_f1(y=FtMg=MVwdbmr<9{(^B12Rr^~Cq@oBImy~J4dRsrqle>`hkr6Gp3F36qIYzNJh%>89x@6vHA}C9s7Qd-XLZLA_CM-6T zGjJxQ-Y1IFrs$O>kr?9n7$tAg;h^hFk`Or2UsDU^gpo=!hvR(+ ziFlDX*nq-3q$5a`K{}0wL-_;pNgSb25MmVy{1hQJqKYNNW=Lq3^wTsC#YXWPO6!sm z76(fq?t-@jPl6XAGx;!x2YcydiXrFnT+(j zix{Z_>kKr|1N5}7f$pd~^uY%3jWC94Y$Nc~NG}){#$aus4YC>JPxR5?nq?^LLl_5N zVm)X^1bh^HSi(dYz~>CCgAP~^Gr%HY*YWCT46g##NNB7TmIQ+e*h(}J+MpIp1ZJU4 z)3z0bl|fb17U4NkFkOnZk|Mf5gPK8o*istk)-fzYVOa-wFrBivN`}@JilBqAP4+by zijM`_QrK3ZV0mZ@t##8D+s_r+QUB!^0)N-^Oc$#(>=|7c0GGD+zMj*WZ#!w$t>HKC>z*|hZ!dSNc$Zm$hD|1z;rb%IVi zUfIarzIXe_YqzxT{L=s7!_B{OXMER)$v*Sb zj{W5ITX_NVV9#&0XFk94?lO9PZhcbtsBRWA-#Y+OB~BR|f?WyDI}MHT9i^U*hp`uhx-Qq<{I^k`E^ zY|m9`wH-3f6?dKe9a+1yp?cpNDXLl5G#g*7_;UZ*h@wFwdJc>1mb~rjeLokMj`pva zSv}zL&GXaaSH*W3KfY6N`d4nVH~R0O3%CE{Qo+gd_bT+`PY-G5=~h)MU;m`*s}sj(CDd0;=@v9N_J@NDE5cUYzQ;Jl_LLT^sZGoN z_vYP)jB%oKQ!C%O@_{~d!PL4k-+@2*cXE65)y|V2@85m6deVBjme~{-+UC(U^Rv>u zjjcZk+0wZ=-avuW?j$^)(IfyJ(59R zHfWM1C`O|AGiZZCwu)0*1Q_TN+A_ev?h!t`KL8jGx-N2l;p{SdU~Z7y}ZxRlXp@K1snCBx4D(ALw@>nMh zp-}k6LE8pA>~6O( zbL|uo2coA%US~7}!F#D^&@c&!&NnHMQY0m(Yu5N0IDQBKE$iJi)x>E; z0P#f#)LVaqlx1m_&=5^DfO_yF3<8a1NwgUbG#VjrM;b$+K<~iEAk^E8CPka+$R|f0 zf1XB?=$+D$M#Jtq@JY~x(UHb7&E!caw%NLrqB$Q0*BJ+SG^J=^4QVqzQh_|@FqfhM zG{ev4Q-mOz`3l{8oAJ>yS+g}*cx`l$M?;KrprOy+Zr^y5Qm5xk`2PoC291%Bz$ryQ jEXrtv!;Ra~x-3o$4-B1H5b8viRO literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.png new file mode 100644 index 0000000000000000000000000000000000000000..c6c6344552a4427255b25a7b2c590f941e5136eb GIT binary patch literal 1342 zcmeAS@N?(olHy`uVBq!ia0y~yVB!U`y*b!`yFLNoKk6ba8o zIw^?@ryMzSNasd{S8$lwsho(;-qtDYy{t1O{GVz{FY2^8l5*;Dg~yKntBpv!Mp?%loa_o|g)tFJOJ{1N{z@s62+;lI2KGedxj2?K-cz%!oA zKU~X@ka2fkt#$ain3L`N@2rxmmrmwA6Fb z@9*!QA8clS`TF(g*Vor?E`EN_#MD&P^WOgY`P$*@QvUq-7`ZXYweH`anU|OQFJHS> zx3{K9gx}xZo_=w0@#gaP_x4nO*8{5XUmA3>jaPb8?eA|_u3dX}VxscP z_wUbNTN{1((j|~x%Y#;?+}@V^^4+_0GYpf99vo==^6eX+i?hGK|GRs8XHQo5e|EH6 z+_K_BLfqb}sWXk!yVxWSX05uKRl0+p@y~nPnjZ$;;`)B^@$p(yy(T?5)XKeb{rdAa zHYS72zr8(w`O>ATo<(0@UEQ*E>(a%Gm95L(oOp6_a`DGUM|I-&+3elBm)T$I-_xI; zpU*VS4*T}@_VjPxzWL0tD2#Z<^3UeqWd`LdTeGhl)&Kj`nBXx9$V@vqNp)xC=QN-b zo}HU(z2W+;TeAuuAA1V)lB9iIjamM^Iiah=Qm?Ozl{C-0vjC_`(l~9&!i9=cy<80r z+;7Qf5PWracX{QP7lC#E|NYIczQ3>5d(xdfmBk6US5^c@Zb)#f`}1R>ie=T83@abzc5`!jbKT?X>*Imm^N)|eFW|@cXKDwV#KLQ9A}9CD+b`R_yZXYfUTO17 zckawldHL#<)Ryl*K0Y=vH($Pfy}ti^yR+}^?gmEY+&wivjbvqIo7dTvy@{Bn8$Ase z%lt284#c+uU6yrmk!xmF)~RE?(wBi2&zm<-#;Qa^Sk33esj1qa5IsFzpFie5FaW=N z|DFys?dOMw&V2HAb5t_(^8Bi+t6#l-9lSQ|^ViqcOG-%>4ZGzrMaU2ByF>v(5EQO-(J!-^ILo_39EZSe@JX zQcq9Q-C6Q7XqoTqX)2cW|7yOyzdwI-`uSzsx0~-SdwXhS@N%QdPfviBrQY3D8o8q& zahcD|Nmo~gr@y?k^stSt!Ic_Y#(L)b`}=&Ioe$UF`Tgf-@xJ>1^E@Z3@vaG7ef7$f zD^Gxa`uXMMUE#_5)?+J@XhCx;oex7Ib6` c3dRX}rzRWA%Mu?C0}DU~Pgg&ebxsLQ0GWe%vH$=8 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg new file mode 100644 index 000000000000..d6de7e425c6f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg @@ -0,0 +1,155 @@ + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4b1893c6b4cd5b49985492dd27aa3d3d8e0d8555 GIT binary patch literal 10634 zcmeHNX + + + + + + + + + + + + + + + + + + + + + + + + 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.png new file mode 100644 index 0000000000000000000000000000000000000000..71d7922248d8fb4cdf700acbe5f47761cb4f6f28 GIT binary patch literal 2769 zcmcImi9eL<9)D4YGdVX~B+??&k>zHIEG5z~sKyw^l3mBxvP44D$+48>Fxi>x!we>S zLza`{Ff_=%gk&enWQk$MeY*GaxqrdE@8?~f_xXI@_j!Kb<@fu=+%YqP2}lY+5ClWq zHn;~t+%PaU;pYYS&B*Ex;BmxXA7Q}{j!=G=Xz+f__qMe^1PM9*xVVb-NWVgmfIq_E zhDC7J>cmqddRwNQIXt(}sG)3W`9METp>D&-ThT37|3dvit18YKcf}pfzFUU1wozkE z=S3nl>U=*)oUKo)xqI2s@OB;JjAtTqhWjW+K9{1V=y#Mh$#IyZ)^#;Xz4`q9``*aN z2yMM5VP9NHcOg`_eReyfksE?e8vf;C4)%tGMSz_<@aJ-YIsFGZF5Q-^-KY0o6|9tvwCJSk*GV0;#F=lG~GD@#rBZVl?=zJdA+gxZLFhZgFo7GN3hbsC! z%CL8=WeT=Fpd>Ofa%(X^fm~Ook>fV`?s5K3|L`zrZOuDdHw;TMe=S|{+C-PNc#c8T z8DGb`yOU0wIN?$?svkeY3=VA`9vFB4jsY51T4)5XgJg7cbni1BJ`r(o($3B!o$UeC z%rdE=!Ny#VUG3IGEE}X?RvN!g_OrHEYFxX-0s{hem$j~4oAbR2K3NzJpZ}0PRv$>2 z@6J9I5GyFID6gq${rK_Yq=M2?h1E|qf7{KY$`$;u7S+V0q&&NZM+iy#qw;XLguhJP zC%>28&Fn{rzTBHpTRY=El(%oKqJ(6IGJTqsC|z{=$9YC3&sZkIZFQ{1Bqk>2MtgL8 z{7{i;=BtzxIfOA1X@SF0y0bK|%FYWNKC2x%*q z>&BnHR`l!{SDAeywr@jb&;50nr5OqJWan$*c{Nql2ScUSTwdY|RyiC__ykzs#(t1i zb|;;F*WR9(m&XaJwY_&QDIAFQAw#0&uW5tZ4jI89N|y?&EzbUWLPNrf7Xs->IkbgE zF#y?~iV+l3xMO3JS>DVEL9~u57=^e2+22!9QNh-FTK95LD3qwMaQ=r6$mW$QH-_ZH zeL4IF@M_Vs)+nKsj>L1U=_nZy2?af4hXXoMRX<=z;*}G|DZr~b8|_m%QBqZ-Cg`( zY*Ul&=;|X^7nkDdYKx?;J`*Llp57Goho$`&x?xvEI;VXXNW}TA_x_CK}y3E#5MFRuw{7AP_ME zf`S(iK*+K4dDm*py{aAY&;xLXb=__ z7P)fe%9X&CvN{fK=IO?td}EcaFQ6l)~!IqbgZ*XL!*zl!T+%Bzk`i`GpCCD0T?%h&90BBE;5xP2A zUsQA}X!7xb0aBtx6a>55WBV@n?y&unvd*rqy8GZBSbF7WcHvQu3BcYQZ zr-OBj6jM$5Ho7A?9L^tV1V?~(2ng@kPc5n~YsbzYL8dNw^X3l5E-;xG`VBFac`h?E z6BwpI(|>-kP5i!vr)OzMNXYD?2G<(w^C4Arb#h~)9h1qd#Fnvu&I0>QHGcnu=7Lh4 z3%U4FPdR%ex9%)BWsnRkVA!{@lwhvSj2J4nqkR49IpqkbMAX#O$l`!P$Yk;WNZ~i5 zj+ammK}LQp-J zj52B0+0rq zNk_-dC|-)WUrHhwfs#7b5JWw{L~Z6IwN7sc{&ZOSkY>vQJ```gtcw|9FsVCh6QCYl1?Iy29V?Mk5D{@CY=5;5)H+;m2FRvm)>XG)FqqWW zBMu*|eudtT+$QN~Fx;#a#9+sdvl?^AWo4$D^9(`j{(*r4kVgjx27KQL<5gyUL<@=m zrL+`TQBhG3tQa_K7qq9lva-_8VeilR(YC&IDd7$|Y-3YXG-x$?GoquX4~4a*6V{dG zA>|i8aC}M>*fW3r{JCGl#2C$=hl|JM%ezunz8jmq}wF8SSwbkOBN2tzZ2a(##2{smR6PX_=1 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg new file mode 100644 index 000000000000..d0bfafd18933 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg @@ -0,0 +1,321 @@ + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ebb19238ee20ac9edb701dea6498490333fdec7b GIT binary patch literal 4482 zcmb_g2~-qE8eUddv^C;^qA_vHC=t}5?`cL66_`Q1AYce9pf)oNGYB&{)5Jla5>eL! zHF#xllX#K!LRS~fg$Mc&k0&AC`U0-^t($d?$G(JR>+hL{;n020EWCPE_19nj-St&X zU|f_zLx*rg;Ep;}T29c2LbkL_A}kD%6Z3K;L`I6Tm}SdAWSp2GIS_*x;!$`wAz4kp z80xVhDK;%rGRjC$c<=^Umh4u^5V9B%@?3D$0PxOHLV)G1*vbgu9P)_c16H zk$R^bogj;{ggBRg1hZ(eSTm5;CEj4O%7|6QP3F)PCa4ZXVh+hFJCM$`!{re8fyj8t zVav4}u}9!RJh*4aye|I;a=c`+h!Hj?wiYC^LMY-nY*mvckf|y%ShBFEh%{tjbE71q z&4e|KldKuC8PO0@C1MWQE{WNM^Rs2k$967=>!iPvsuvFJnLXw2=cX>IUexKcZUq$| z{jOyC&xwoJ#Y=0l9kb$(b~Fzudc0^pDRv&PExLQWD4h922kx4;uf?C~` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CF>sFZSHi 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg new file mode 100644 index 000000000000..81fdc24a16ab --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg @@ -0,0 +1,117 @@ + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3e0b0d5768a1ff8575367086ffab0d1cbaf8c465 GIT binary patch literal 10213 zcmeHNXIxar7Pk^y!52_tjb430kO+Ir-g|cwRJzhsN)!u*1r}HXySOZ7O)ODBC0L?@ z4Qo^sF;USNHJXSG3s{H&8!-xMh{nW{V8rs~% + + + + + + + + + + + + + + + + + + + + + + + + D=>&}kB8WkQ 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.png new file mode 100644 index 0000000000000000000000000000000000000000..f18cba313e4d8d134936cfcb29158762f7217cac GIT binary patch literal 2664 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 + + + diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 84973ed289a8..63689cd27157 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -2,6 +2,7 @@ import matplotlib from matplotlib.testing.decorators import image_comparison, knownfailureif import matplotlib.pyplot as plt +from matplotlib import mathtext math_tests = [ r'$a+b+\dots+\dot{s}+\ldots$', @@ -46,7 +47,6 @@ r'$\widehat{abc}\widetilde{def}$', r'$\Gamma \Delta \Theta \Lambda \Xi \Pi \Sigma \Upsilon \Phi \Psi \Omega$', r'$\alpha \beta \gamma \delta \epsilon \zeta \eta \theta \iota \lambda \mu \nu \xi \pi \kappa \rho \sigma \tau \upsilon \phi \chi \psi$', - # r'$\operatorname{cos} x$', # The examples prefixed by 'mmltt' are from the MathML torture test here: # http://www.mozilla.org/projects/mathml/demo/texvsmml.xhtml @@ -59,7 +59,6 @@ r'${a}_{0}+\frac{1}{{a}_{1}+\frac{1}{{a}_{2}+\frac{1}{{a}_{3}+\frac{1}{{a}_{4}}}}}$', r'$\binom{n}{k/2}$', r'$\binom{p}{2}{x}^{2}{y}^{p-2}-\frac{1}{1-x}\frac{1}{1-{x}^{2}}$', - # 'mmltt10' : r'$\sum _{\genfrac{}{}{0}{}{0\leq i\leq m}{0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Thu, 27 Oct 2011 12:49:37 -0400 Subject: [PATCH 214/214] Fix bug where arrow paths were not being closed correctly with a CLOSEPOLY command. (Showed up only in PDF output). Reported by moglii --- lib/matplotlib/patches.py | 19 ++++++++++--------- lib/matplotlib/path.py | 7 ++++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 36b3ff1fba68..824e114d3b55 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -790,7 +790,7 @@ def set_closed(self, closed): def get_xy(self): return self._path.vertices def set_xy(self, vertices): - self._path = Path(vertices) + self._path = Path(vertices, closed=self._closed) _get_xy = get_xy _set_xy = set_xy xy = property( @@ -871,7 +871,8 @@ def __str__(self): [ 0.0, 0.1 ], [ 0.0, -0.1], [ 0.8, -0.1 ], [ 0.8, -0.3], [ 1.0, 0.0 ], [ 0.8, 0.3], - [ 0.8, 0.1 ], [ 0.0, 0.1] ] ) + [ 0.8, 0.1 ], [ 0.0, 0.1] ], + closed=True) @docstring.dedent_interpd def __init__( self, x, y, dx, dy, width=1.0, **kwargs ): @@ -979,7 +980,7 @@ def __init__(self, x, y, dx, dy, width=0.001, length_includes_head=False, \ M = np.array([[cx, sx],[-sx,cx]]) verts = np.dot(coords, M) + (x+dx, y+dy) - Polygon.__init__(self, map(tuple, verts), **kwargs) + Polygon.__init__(self, map(tuple, verts), closed=True, **kwargs) docstring.interpd.update({"FancyArrow":FancyArrow.__init__.__doc__}) @@ -1051,7 +1052,7 @@ def get_path(self): xs = self.convert_xunits([xb1, xb2, xc2, xd2, x1, xd1, xc1, xb1]) ys = self.convert_yunits([yb1, yb2, yc2, yd2, y1, yd1, yc1, yb1]) - return Path(zip(xs, ys)) + return Path(zip(xs, ys), closed=True) def get_patch_transform(self): return transforms.IdentityTransform() @@ -3696,7 +3697,7 @@ def set_dpi_cor(self, dpi_cor): dpi_cor is currently used for linewidth-related things and shink factor. Mutation scale is not affected by this. """ - + self._dpi_cor = dpi_cor def get_dpi_cor(self): @@ -3704,10 +3705,10 @@ def get_dpi_cor(self): dpi_cor is currently used for linewidth-related things and shink factor. Mutation scale is not affected by this. """ - + return self._dpi_cor - + def set_positions(self, posA, posB): """ set the begin end end positions of the connecting path. Use current vlaue if None. @@ -3905,7 +3906,7 @@ def draw(self, renderer): # FIXME : dpi_cor is for the dpi-dependecy of the # linewidth. There could be room for improvement. - # + # #dpi_cor = renderer.points_to_pixels(1.) self.set_dpi_cor(renderer.points_to_pixels(1.)) path, fillable = self.get_path_in_displaycoord() @@ -4167,7 +4168,7 @@ def get_path_in_displaycoord(self): """ dpi_cor = self.get_dpi_cor() - + x, y = self.xy1 posA = self._get_xy(x, y, self.coords1, self.axesA) diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index 82f20c449a56..81a4118e10a6 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -80,7 +80,7 @@ class Path(object): code_type = np.uint8 - def __init__(self, vertices, codes=None, _interpolation_steps=1): + def __init__(self, vertices, codes=None, _interpolation_steps=1, closed=False): """ Create a new path with the given vertices and codes. @@ -117,6 +117,11 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1): assert len(codes) == len(vertices) if len(codes): assert codes[0] == self.MOVETO + elif closed: + codes = np.empty(len(vertices)) * 2 + codes[0] = self.MOVETO + codes[1:-1] = self.LINETO + codes[-1] = self.CLOSEPOLY assert vertices.ndim == 2 assert vertices.shape[1] == 2