Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

If path clipping introduces MOVETO operations, change final CLOSEPOLY to LINETO #817

Merged
merged 1 commit into from

2 participants

@jkseppan
Collaborator

This is for issue #804: logarithmic histograms look wrong in pdf and svg, because clipping negative values introduces MOVETO operations so CLOSEPOLY draws a line to an intermediate node instead of the intended first node. Requesting review from @mdboom.

@mdboom
Owner

Looks good to me. Thanks for finding this. Do you agree it's ready to merge?

@jkseppan
Collaborator

I think it is. It passes all tests except for some knownfails.

@jkseppan jkseppan merged commit 376dcb8 into matplotlib:v1.1.x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 6, 2012
  1. @jkseppan
This page is out of date. Refresh to see the latest.
View
6 CHANGELOG
@@ -1,3 +1,9 @@
+2012-04-06 When path clipping changes a LINETO to a MOVETO, it also
+ changes any CLOSEPOLY command to a LINETO to the initial
+ point. This fixes a problem with pdf and svg where the
+ CLOSEPOLY would then draw a line to the latest MOVETO
+ position instead of the intended initial position. - JKS
+
2012-01-23 The radius labels in polar plots no longer use a fixed
padding, but use a different alignment depending on the
quadrant they are in. This fixes numerical problems when
View
BIN  lib/matplotlib/tests/baseline_images/test_axes/hist_log.pdf
Binary file not shown
View
BIN  lib/matplotlib/tests/baseline_images/test_axes/hist_log.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
343 lib/matplotlib/tests/baseline_images/test_axes/hist_log.svg
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Created with matplotlib (http://matplotlib.sourceforge.net/) -->
+<svg height="432pt" version="1.1" viewBox="0 0 576 432" width="576pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <style type="text/css">
+*{stroke-linecap:square;stroke-linejoin:round;}
+ </style>
+ </defs>
+ <g id="figure_1">
+ <g id="patch_1">
+ <path d="
+M0 432
+L576 432
+L576 0
+L0 0
+z
+" style="fill:#ffffff;"/>
+ </g>
+ <g id="axes_1">
+ <g id="patch_2">
+ <path d="
+M72 388.8
+L518.4 388.8
+L518.4 43.2
+L72 43.2
+z
+" style="fill:#ffffff;"/>
+ </g>
+ <g id="patch_3">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M72 17841.6
+M116.64 433
+L116.64 358.371
+L72 358.371
+L72 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_4">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M116.64 17841.6
+M161.28 433
+L161.28 348.978
+L116.64 348.978
+L116.64 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_5">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M161.28 17841.6
+M205.92 433
+L205.92 333.121
+L161.28 333.121
+L161.28 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_6">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M205.92 17841.6
+M250.56 433
+L250.56 306.353
+L205.92 306.353
+L205.92 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_7">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M250.56 17841.6
+M295.2 433
+L295.2 204.862
+L250.56 204.862
+L250.56 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_8">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M295.2 17841.6
+M339.84 433
+L339.84 203.579
+L295.2 203.579
+L295.2 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_9">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M339.84 17841.6
+M384.48 433
+L384.48 306.353
+L339.84 306.353
+L339.84 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_10">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M384.48 17841.6
+M429.12 433
+L429.12 333.121
+L384.48 333.121
+L384.48 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_11">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M429.12 17841.6
+M473.76 433
+L473.76 348.978
+L429.12 348.978
+L429.12 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_12">
+ <path clip-path="url(#p7ff5b81e1d)" d="
+M473.76 17841.6
+M518.4 433
+L518.4 358.371
+L473.76 358.371
+L473.76 17841.6" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="matplotlib.axis_1"/>
+ <g id="matplotlib.axis_2">
+ <g id="ytick_1">
+ <g id="line2d_1">
+ <defs>
+ <path d="
+M0 0
+L2 0" id="md1aed85dae" style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;"/>
+ </defs>
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="336.782016749"/>
+ </g>
+ </g>
+ <g id="line2d_2">
+ <defs>
+ <path d="
+M0 0
+L-2 0" id="m544cce01ee" style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;"/>
+ </defs>
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="336.782016749"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_2">
+ <g id="line2d_3">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="306.353447184"/>
+ </g>
+ </g>
+ <g id="line2d_4">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="306.353447184"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_3">
+ <g id="line2d_5">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="284.764033499"/>
+ </g>
+ </g>
+ <g id="line2d_6">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="284.764033499"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_4">
+ <g id="line2d_7">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="268.017983251"/>
+ </g>
+ </g>
+ <g id="line2d_8">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="268.017983251"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_5">
+ <g id="line2d_9">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="254.335463934"/>
+ </g>
+ </g>
+ <g id="line2d_10">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="254.335463934"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_6">
+ <g id="line2d_11">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="242.767058686"/>
+ </g>
+ </g>
+ <g id="line2d_12">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="242.767058686"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_7">
+ <g id="line2d_13">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="232.746050248"/>
+ </g>
+ </g>
+ <g id="line2d_14">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="232.746050248"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_8">
+ <g id="line2d_15">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="223.906894369"/>
+ </g>
+ </g>
+ <g id="line2d_16">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="223.906894369"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_9">
+ <g id="line2d_17">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="163.982016749"/>
+ </g>
+ </g>
+ <g id="line2d_18">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="163.982016749"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_10">
+ <g id="line2d_19">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="133.553447184"/>
+ </g>
+ </g>
+ <g id="line2d_20">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="133.553447184"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_11">
+ <g id="line2d_21">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="111.964033499"/>
+ </g>
+ </g>
+ <g id="line2d_22">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="111.964033499"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_12">
+ <g id="line2d_23">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="95.2179832507"/>
+ </g>
+ </g>
+ <g id="line2d_24">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="95.2179832507"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_13">
+ <g id="line2d_25">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="81.5354639337"/>
+ </g>
+ </g>
+ <g id="line2d_26">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="81.5354639337"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_14">
+ <g id="line2d_27">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="69.9670586855"/>
+ </g>
+ </g>
+ <g id="line2d_28">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="69.9670586855"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_15">
+ <g id="line2d_29">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="59.9460502478"/>
+ </g>
+ </g>
+ <g id="line2d_30">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="59.9460502478"/>
+ </g>
+ </g>
+ </g>
+ <g id="ytick_16">
+ <g id="line2d_31">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="72.0" xlink:href="#md1aed85dae" y="51.1068943689"/>
+ </g>
+ </g>
+ <g id="line2d_32">
+ <g>
+ <use style="stroke:#000000;stroke-linecap:butt;stroke-width:0.5;" x="518.4" xlink:href="#m544cce01ee" y="51.1068943689"/>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g id="patch_13">
+ <path d="
+M72 43.2
+L518.4 43.2" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_14">
+ <path d="
+M518.4 388.8
+L518.4 43.2" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_15">
+ <path d="
+M72 388.8
+L518.4 388.8" style="fill:none;stroke:#000000;"/>
+ </g>
+ <g id="patch_16">
+ <path d="
+M72 388.8
+L72 43.2" style="fill:none;stroke:#000000;"/>
+ </g>
+ </g>
+ </g>
+ <defs>
+ <clipPath id="p7ff5b81e1d">
+ <rect height="345.6" width="446.4" x="72.0" y="43.2"/>
+ </clipPath>
+ </defs>
+</svg>
View
9 lib/matplotlib/tests/test_axes.py
@@ -631,6 +631,15 @@ def test_markevery_line():
ax.plot(x, y, '-+', markevery=(5, 20), label='mark every 5 starting at 10')
ax.legend()
+@image_comparison(baseline_images=['hist_log'])
+def test_hist_log():
+ data0 = np.linspace(0,1,200)**3
+ data = np.r_[1-data0, 1+data0]
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ ax.hist(data, fill=False, log=True)
+ ax.set_xticks([])
+ ax.set_yticks([])
if __name__=='__main__':
import nose
View
26 lib/matplotlib/tests/test_transforms.py
@@ -1,6 +1,8 @@
from nose.tools import assert_equal
from numpy.testing import assert_almost_equal
-from matplotlib.transforms import Affine2D
+from matplotlib.transforms import Affine2D, BlendedGenericTransform
+from matplotlib.path import Path
+from matplotlib.scale import LogScale
import numpy as np
def test_Affine2D_from_values():
@@ -38,3 +40,25 @@ def test_Affine2D_from_values():
actual = t.transform(points)
expected = np.array( [[0,6],[0,6],[0,6]] )
assert_almost_equal(actual,expected)
+
+def test_clipping_of_log():
+ # issue 804
+ M,L,C = Path.MOVETO, Path.LINETO, Path.CLOSEPOLY
+ points = [ (0.2, -99), (0.4, -99), (0.4, 20), (0.2, 20), (0.2, -99) ]
+ codes = [ M, L, L, L, C ]
+ path = Path(points, codes)
+
+ # something like this happens in plotting logarithmic histograms
+ trans = BlendedGenericTransform(Affine2D(),
+ LogScale.Log10Transform('clip'))
+ tpath = trans.transform_path_non_affine(path)
+ result = tpath.iter_segments(trans.get_affine(),
+ clip=(0, 0, 100, 100),
+ simplify=False)
+
+ tpoints, tcodes = zip(*result)
+ # Because y coordinate -99 is outside the clip zone, the first
+ # line segment is effectively removed. That means that the closepoly
+ # operation must be replaced by a move to the first point.
+ assert np.allclose(tcodes, [ M, M, L, L, L ])
+ assert np.allclose(tpoints[-1], tpoints[0])
View
23 src/path_converters.h
@@ -285,13 +285,17 @@ class PathClipper
double m_nextX;
double m_nextY;
bool m_has_next;
+ double m_initX;
+ double m_initY;
+ bool m_has_init;
+ bool m_broke_path;
public:
PathClipper(VertexSource& source, bool do_clipping,
double width, double height) :
m_source(&source), m_do_clipping(do_clipping),
m_cliprect(-1.0, -1.0, width + 1.0, height + 1.0), m_moveto(true),
- m_has_next(false)
+ m_has_next(false), m_has_init(false), m_broke_path(false)
{
// empty
}
@@ -299,7 +303,8 @@ class PathClipper
PathClipper(VertexSource& source, bool do_clipping,
const agg::rect_base<double>& rect) :
m_source(&source), m_do_clipping(do_clipping),
- m_cliprect(rect), m_moveto(true), m_has_next(false)
+ m_cliprect(rect), m_moveto(true), m_has_next(false),
+ m_has_init(false), m_broke_path(false)
{
m_cliprect.x1 -= 1.0;
m_cliprect.y1 -= 1.0;
@@ -334,6 +339,12 @@ class PathClipper
while ((code = m_source->vertex(x, y)) != agg::path_cmd_stop)
{
+ if (!m_has_init)
+ {
+ m_initX = *x;
+ m_initY = *y;
+ m_has_init = true;
+ }
if (m_moveto)
{
m_moveto = false;
@@ -362,6 +373,7 @@ class PathClipper
m_nextX = x1;
m_nextY = y1;
m_has_next = true;
+ m_broke_path = true;
return agg::path_cmd_move_to;
}
*x = x1;
@@ -369,6 +381,13 @@ class PathClipper
return code;
}
}
+ else if (code == agg::path_cmd_end_poly | agg::path_flags_close
+ && m_broke_path && m_has_init)
+ {
+ *x = m_initX;
+ *y = m_initY;
+ return agg::path_cmd_line_to;
+ }
else
{
break;
Something went wrong with that request. Please try again.