Skip to content

Commit 6a5ec42

Browse files
authored
Merge pull request #284 from nschloe/patch-edges
Patch edges
2 parents 850907b + 1113980 commit 6a5ec42

11 files changed

+216
-148
lines changed

matplotlib2tikz/line2d.py

Lines changed: 8 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ def draw_line2d(data, obj):
2424
return data, []
2525

2626
# get the linewidth (in pt)
27-
line_width = _mpl_linewidth2pgfp_linewidth(data, obj.get_linewidth())
28-
27+
line_width = mypath.mpl_linewidth2pgfp_linewidth(data, obj.get_linewidth())
2928
if line_width:
3029
addplot_options.append(line_width)
3130

@@ -38,8 +37,8 @@ def draw_line2d(data, obj):
3837
if alpha is not None:
3938
addplot_options.append("opacity={}".format(alpha))
4039

41-
show_line, linestyle = _mpl_linestyle2pgfp_linestyle(obj.get_linestyle())
42-
if show_line and linestyle:
40+
linestyle = mypath.mpl_linestyle2pgfplots_linestyle(obj.get_linestyle())
41+
if linestyle is not None and linestyle != "solid":
4342
addplot_options.append(linestyle)
4443

4544
marker_face_color = obj.get_markerfacecolor()
@@ -59,7 +58,7 @@ def draw_line2d(data, obj):
5958
line_xcolor,
6059
)
6160

62-
if marker and not show_line:
61+
if marker and linestyle is None:
6362
addplot_options.append("only marks")
6463

6564
# Check if a line is in a legend and forget it if not.
@@ -92,51 +91,11 @@ def draw_linecollection(data, obj):
9291
paths = obj.get_paths()
9392

9493
for i, path in enumerate(paths):
95-
if i < len(edgecolors):
96-
color = edgecolors[i]
97-
else:
98-
color = edgecolors[0]
99-
100-
if i < len(linestyles):
101-
style = linestyles[i]
102-
else:
103-
style = linestyles[0]
104-
105-
if i < len(linewidths):
106-
width = linewidths[i]
107-
else:
108-
width = linewidths[0]
109-
110-
data, options = mypath.get_draw_options(data, color, None)
111-
112-
width = _mpl_linewidth2pgfp_linewidth(data, width)
113-
if width:
114-
options.append(width)
115-
116-
# linestyle is a string or dash tuple. Legal string values are
117-
# solid|dashed|dashdot|dotted. The dash tuple is (offset, onoffseq)
118-
# where onoffseq is an even length tuple of on and off ink in points.
119-
#
120-
# solid: [(None, None), (None, None), ..., (None, None)]
121-
# dashed: (0, (6.0, 6.0))
122-
# dotted: (0, (1.0, 3.0))
123-
# dashdot: (0, (3.0, 5.0, 1.0, 5.0))
124-
if style[0] is not None:
125-
assert isinstance(style, tuple)
126-
if len(style[1]) == 2:
127-
linestyle = "dash pattern=on {:d}pt off {:d}pt".format(
128-
int(style[1][0]), int(style[1][1])
129-
)
130-
else:
131-
assert len(style[1]) == 4
132-
linestyle = "dash pattern=on {:d}pt off {:d}pt on {:d}pt off {:d}pt".format(
133-
int(style[1][0]),
134-
int(style[1][1]),
135-
int(style[1][2]),
136-
int(style[1][3]),
137-
)
94+
color = edgecolors[i] if i < len(edgecolors) else edgecolors[0]
95+
style = linestyles[i] if i < len(linestyles) else linestyles[0]
96+
width = linewidths[i] if i < len(linewidths) else linewidths[0]
13897

139-
options.append(linestyle)
98+
data, options = mypath.get_draw_options(data, obj, color, None, style, width)
14099

141100
# TODO what about masks?
142101
data, cont, _, _ = mypath.draw_path(
@@ -147,51 +106,6 @@ def draw_linecollection(data, obj):
147106
return data, content
148107

149108

150-
TIKZ_LINEWIDTHS = {
151-
0.1: "ultra thin",
152-
0.2: "very thin",
153-
0.4: "thin",
154-
0.6: "semithick",
155-
0.8: "thick",
156-
1.2: "very thick",
157-
1.6: "ultra thick",
158-
}
159-
160-
161-
def _mpl_linewidth2pgfp_linewidth(data, line_width):
162-
if data["strict"]:
163-
# Takes the matplotlib linewidths, and just translate them
164-
# into PGFPlots.
165-
try:
166-
return TIKZ_LINEWIDTHS[line_width]
167-
except KeyError:
168-
# explicit line width
169-
return "line width={}pt".format(line_width)
170-
else:
171-
# The following is an alternative approach to line widths.
172-
# The default line width in matplotlib is 1.0pt, in PGFPlots 0.4pt
173-
# ('thin').
174-
# Match the two defaults, and scale for the rest.
175-
scaled_line_width = line_width / 1.0 # scale by default line width
176-
literals = {
177-
0.25: "ultra thin",
178-
0.5: "very thin",
179-
1.0: None, # default, 'thin'
180-
1.5: "semithick",
181-
2: "thick",
182-
3: "very thick",
183-
4: "ultra thick",
184-
}
185-
186-
try:
187-
out = literals[scaled_line_width]
188-
except KeyError:
189-
# explicit line width
190-
out = "line width={}pt".format(0.4 * line_width)
191-
192-
return out
193-
194-
195109
# for matplotlib markers, see: http://matplotlib.org/api/markers_api.html
196110
_MP_MARKER2PGF_MARKER = {
197111
".": "*", # point
@@ -263,26 +177,6 @@ def _mpl_marker2pgfp_marker(data, mpl_marker, marker_face_color):
263177
return data, None, None
264178

265179

266-
_MPLLINESTYLE_2_PGFPLOTSLINESTYLE = {
267-
"": None,
268-
"None": None,
269-
"none": None, # happens when using plt.boxplot()
270-
"-": None,
271-
":": "dotted",
272-
"--": "dashed",
273-
"-.": "dash pattern=on 1pt off 3pt on 3pt off 3pt",
274-
}
275-
276-
277-
def _mpl_linestyle2pgfp_linestyle(line_style):
278-
"""Translates a line style of matplotlib to the corresponding style
279-
in PGFPlots.
280-
"""
281-
show_line = line_style != "None"
282-
style = _MPLLINESTYLE_2_PGFPLOTSLINESTYLE[line_style]
283-
return show_line, style
284-
285-
286180
# def _transform_to_data_coordinates(obj, xdata, ydata):
287181
# '''The coordinates might not be in data coordinates, but could be partly
288182
# in axes coordinates. For example, the matplotlib command
@@ -425,5 +319,4 @@ def _table(obj, content, data):
425319
content.extend(plot_table)
426320

427321
content.append("};\n")
428-
429322
return

matplotlib2tikz/patch.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ def draw_patch(data, obj):
1010
"""
1111
# Gather the draw options.
1212
data, draw_options = mypath.get_draw_options(
13-
data, obj.get_edgecolor(), obj.get_facecolor()
13+
data,
14+
obj,
15+
obj.get_edgecolor(),
16+
obj.get_facecolor(),
17+
obj.get_linestyle(),
18+
obj.get_linewidth(),
1419
)
1520

1621
if isinstance(obj, mpl.patches.Rectangle):
@@ -33,16 +38,26 @@ def draw_patchcollection(data, obj):
3338
content = []
3439
# Gather the draw options.
3540
try:
36-
edge_color = obj.get_edgecolor()[0]
41+
ec = obj.get_edgecolor()[0]
3742
except IndexError:
38-
edge_color = None
43+
ec = None
3944

4045
try:
41-
face_color = obj.get_facecolor()[0]
46+
fc = obj.get_facecolor()[0]
4247
except IndexError:
43-
face_color = None
48+
fc = None
4449

45-
data, draw_options = mypath.get_draw_options(data, edge_color, face_color)
50+
try:
51+
ls = obj.get_linestyle()[0]
52+
except IndexError:
53+
ls = None
54+
55+
try:
56+
w = obj.get_linewidth()[0]
57+
except IndexError:
58+
w = None
59+
60+
data, draw_options = mypath.get_draw_options(data, obj, ec, fc, ls, w)
4661

4762
paths = obj.get_paths()
4863
for path in paths:

matplotlib2tikz/path.py

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,26 +137,30 @@ def draw_pathcollection(data, obj):
137137
table_options.extend(["x=x", "y=y", "meta=colordata"])
138138
ec = None
139139
fc = None
140+
ls = None
140141
else:
141142
# gather the draw options
142-
ec = obj.get_edgecolors()
143-
fc = obj.get_facecolors()
144143
try:
145-
ec = ec[0]
144+
ec = obj.get_edgecolors()[0]
146145
except (TypeError, IndexError):
147146
ec = None
147+
148148
try:
149-
fc = fc[0]
149+
fc = obj.get_facecolors()[0]
150150
except (TypeError, IndexError):
151151
fc = None
152152

153+
try:
154+
ls = obj.get_linestyle()[0]
155+
except (TypeError, IndexError):
156+
ls = None
157+
153158
is_contour = len(dd) == 1
154159
if is_contour:
155160
draw_options = ["draw=none"]
156161

157-
# TODO Use linewidths
158-
# linewidths = obj.get_linewidths()
159-
data, extra_draw_options = get_draw_options(data, ec, fc)
162+
# `only mark` plots don't need linewidth
163+
data, extra_draw_options = get_draw_options(data, obj, ec, fc, ls, None)
160164
draw_options.extend(extra_draw_options)
161165

162166
if obj.get_cmap():
@@ -205,7 +209,7 @@ def draw_pathcollection(data, obj):
205209
return data, content
206210

207211

208-
def get_draw_options(data, ec, fc):
212+
def get_draw_options(data, obj, ec, fc, style, width):
209213
"""Get the draw options for a given (patch) object.
210214
"""
211215
draw_options = []
@@ -236,7 +240,88 @@ def get_draw_options(data, ec, fc):
236240
draw_options.append(("draw opacity=" + ff).format(ec_rgba[3]))
237241
if fc is not None and fc_rgba[3] != 1.0:
238242
draw_options.append(("fill opacity=" + ff).format(fc_rgba[3]))
239-
# TODO Use those properties
240-
# linewidths = obj.get_linewidths()
243+
244+
if width is not None:
245+
w = mpl_linewidth2pgfp_linewidth(data, width)
246+
if w:
247+
draw_options.append(w)
248+
249+
if style is not None:
250+
ls = mpl_linestyle2pgfplots_linestyle(style)
251+
if ls is not None and ls != "solid":
252+
draw_options.append(ls)
241253

242254
return data, draw_options
255+
256+
257+
def mpl_linewidth2pgfp_linewidth(data, line_width):
258+
if data["strict"]:
259+
# Takes the matplotlib linewidths, and just translate them into PGFPlots.
260+
try:
261+
return {
262+
0.1: "ultra thin",
263+
0.2: "very thin",
264+
0.4: "thin",
265+
0.6: "semithick",
266+
0.8: "thick",
267+
1.2: "very thick",
268+
1.6: "ultra thick",
269+
}[line_width]
270+
except KeyError:
271+
# explicit line width
272+
return "line width={}pt".format(line_width)
273+
274+
# The following is an alternative approach to line widths.
275+
# The default line width in matplotlib is 1.0pt, in PGFPlots 0.4pt
276+
# ('thin').
277+
# Match the two defaults, and scale for the rest.
278+
scaled_line_width = line_width / 1.0 # scale by default line width
279+
try:
280+
out = {
281+
0.25: "ultra thin",
282+
0.5: "very thin",
283+
1.0: None, # default, 'thin'
284+
1.5: "semithick",
285+
2: "thick",
286+
3: "very thick",
287+
4: "ultra thick",
288+
}[scaled_line_width]
289+
except KeyError:
290+
# explicit line width
291+
out = "line width={}pt".format(0.4 * line_width)
292+
293+
return out
294+
295+
296+
def mpl_linestyle2pgfplots_linestyle(line_style):
297+
"""Translates a line style of matplotlib to the corresponding style
298+
in PGFPlots.
299+
"""
300+
# linestyle is a string or dash tuple. Legal string values are
301+
# solid|dashed|dashdot|dotted. The dash tuple is (offset, onoffseq) where onoffseq
302+
# is an even length tuple of on and off ink in points.
303+
#
304+
# solid: [(None, None), (None, None), ..., (None, None)]
305+
# dashed: (0, (6.0, 6.0))
306+
# dotted: (0, (1.0, 3.0))
307+
# dashdot: (0, (3.0, 5.0, 1.0, 5.0))
308+
if isinstance(line_style, tuple):
309+
if line_style[0] is None:
310+
return None
311+
312+
if len(line_style[1]) == 2:
313+
return "dash pattern=on {}pt off {}pt".format(*line_style[1])
314+
315+
assert len(line_style[1]) == 4
316+
return "dash pattern=on {}pt off {}pt on {}pt off {}pt".format(*line_style[1])
317+
318+
return {
319+
"": None,
320+
"None": None,
321+
"none": None, # happens when using plt.boxplot()
322+
"-": "solid",
323+
"solid": "solid",
324+
":": "dotted",
325+
"--": "dashed",
326+
"-.": "dash pattern=on 1pt off 3pt on 3pt off 3pt",
327+
}[line_style]

0 commit comments

Comments
 (0)