In the documentation of matplotlib.lines.set_linestyle() and elsewhere in the matplotlib docs it is written that the linestyle can be a dash tuple of the form (offset, onoffseq), where onoffseq is an even length tuple.
Providing the onoffseq works fine, but the offset seems to be ignored, e.g., the following code produces two identical plots:
x = linspace(0,10)
plot(x, ls=( 0, (10,10)))
plot(x, ls=(10, (10,10)))
Indeed it should work as documented, but I am much more concerned about regressions (things that used to work and now do not) than documented features that have never existed. The later is annoying and should be fixed, but the former breaks user code.
There is a comment in the code self._dashSeq = seq # TODO: offset ignored for now which was last touched in 2005 (!).
I was trying to update the following example to demonstrate the possibility of setting the dash style directly through the kwarg linestyle. I was also interested in showing that with the latter method, one can specify the offset of the dash sequence. However by doing this I find two surprising "behaviors".
As I found the current issue ticket about the very same feature, I post here. But if it would be better to open a dedicated new ticket, please let me know.
What is the unit of the dash sequence?
Since the dash lengths are now scaled wrt the line width (PR #5926), is it still correct to say that the dash sequence is given in points? See for example
where the same dash sequence (40, 2, 4, 4) (in "pt") with 2 different linewidths (1pt and 2 pt) gives two different lengths for the dashes. I understand it is the expected behavior but shouldn't the relevant doc be updated. (I haven't really found a nice formulation to propose for this...)
Is a negative value allowed as the offset of a dash sequence?
To demonstrate how to set the offset value of a dash sequence (with (offset, onoffseq)), I adapted the existing example into
importnumpyasnpimportmatplotlib.pyplotaspltdashes= [40, 2, 4, 4] # 40 points on, 2 off, 4 on, 4 offx=np.linspace(0, 10, 500)
y=np.sin(x)
# Set dash style via the Line method `set_dashes`line, =plt.plot(x, y, '--', linewidth=2, color='0.25',
label="set_dashes({0})".format(dashes))
line.set_dashes(dashes)
# Set dash style directly via the `linestyle` keyword argument# NB: The offset `dy` is "manually" adjusted to get a smooth evolution of the# dashes offsets along the line stack.foroffset, dyinzip([-10, -5, 0, 5, 10], [-0.4, -0.2, 0.2, 0.4, 0.6]):
ls= (offset, dashes)
l, =plt.plot(x, y+dy, ls=ls, lw=2, label="ls={0}".format(ls))
plt.legend(loc='lower right', fontsize='small')
plt.axvline(0.95, color='0.8') # to compare the offset values more easilyplt.show()
which results in
It seems to me that the negative offset values (-5 and -10, the two first lines from the bottom) are not correctly handled, are they? (I added a vertical line to help checking.) As I didn't see indicated anywhere that negative values are not allowed for dashes offset, I wonder if it is the expected behavior.
About the documentation update, what about changing a bit the docstring of lines.Line2D.set_linewidth? For example by:
Alternatively a dash tuple of the following form can be provided::
(offset, onoffseq),
where ``onoffseq`` is an even length tuple of on and off ink, in points if the
line width is thiner than 1 pt, and in units of line width if it is larger.
or
Alternatively a dash tuple of the following form can be provided::
(offset, onoffseq),
where ``onoffseq`` is an even length tuple of on and off ink in points. If the
line width is larger than 1 pt, the dash tuple is scaled with respect to the
line width value (in pt).
IMHO, the second one is more precise as the offset value is also scaled by the line width value (see ll. 865-874 in commit 04ffd42)
If one of the formulations is OK, I can submit a PR with this change. As think that some other docstrings will need to be updated as well (at least the ones of set_linestyle in collections.py and backend_bases.py)
@tacaswell : Are you sure that the PDF backend is not working? Because if I simply do a plt.savefig("NiceName.<ext among {png, pdf, svg}>", dpi=100), I have the feeling that only the PNG export is not working. Here are the pictures I got (conversions from PDF and SVG into PNG were done with ImageMagick). PNG: PDF (-> PNG via ImageMagick): SVG (-> PNG via ImageMagick):
PS: I generated the plots with Matplotlib 1.5.2rc2.post1938+g4ba20b8
(2016-06-06) Edit: I had forgotten to precise the type of the pictures... Corrected for the record.
Not sure I understood your last remark. I just tested my PDF with Evince, xpdf, Inkscape (import), qpdfview and MuPDF (everything on Linux), and every viewer was fine. But isn't it the expected behavior and the PDF rationale?
PS : I don't know why but I can't upload on GitHub the PDF I produced in my previous answer. I get an error from GitHub (“Unfortunately, we don’t support that file type. Try again with a PNG, GIF, JPG, DOCX, PPTX, XLSX, TXT, PDF, or ZIP.”)
I think the pdf backend just writes the offset into the pdf file. The pdf specification doesn't seem to explicitly say that the offset must be nonnegative, but I think it is implied. Different viewers could handle it differently.
Here is what I found about dash patterns PDFReference_3rd_ed_pp.175-176_bis.pdf, and indeed the way “dash phase” pattern is handled seems to assume it's a positive quantity : if I understood correctly, a line starts to be drawn when accumulated sum of the patterns is equal to the offset.
A possibility to handle negative values might be to convert them into a equivalent positive value (% length of a complete dash pattern). Something like
Activity
tacaswell commented on Nov 7, 2015
@mkrphys Did this ever work? What version of mpl are you using?
is a little easier to see that offset has no effect.
tacaswell commented on Nov 7, 2015
Indeed it should work as documented, but I am much more concerned about regressions (things that used to work and now do not) than documented features that have never existed. The later is annoying and should be fixed, but the former breaks user code.
There is a comment in the code self._dashSeq = seq # TODO: offset ignored for now which was last touched in 2005 (!).
tacaswell commented on Nov 7, 2015
See #5433 which will pass the value through, but the Agg backend does not do seem to do anything with it during rendering.
afvincent commented on Jun 1, 2016
I was trying to update the following example to demonstrate the possibility of setting the dash style directly through the kwarg linestyle. I was also interested in showing that with the latter method, one can specify the offset of the dash sequence. However by doing this I find two surprising "behaviors".
As I found the current issue ticket about the very same feature, I post here. But if it would be better to open a dedicated new ticket, please let me know.
What is the unit of the dash sequence?
Since the dash lengths are now scaled wrt the line width (PR #5926), is it still correct to say that the dash sequence is given in points? See for example

where the same dash sequence (40, 2, 4, 4) (in "pt") with 2 different linewidths (1pt and 2 pt) gives two different lengths for the dashes. I understand it is the expected behavior but shouldn't the relevant doc be updated. (I haven't really found a nice formulation to propose for this...)
Is a negative value allowed as the offset of a dash sequence?
To demonstrate how to set the offset value of a dash sequence (with (offset, onoffseq)), I adapted the existing example into
which results in

It seems to me that the negative offset values (-5 and -10, the two first lines from the bottom) are not correctly handled, are they? (I added a vertical line to help checking.) As I didn't see indicated anywhere that negative values are not allowed for dashes offset, I wonder if it is the expected behavior.
tacaswell commented on Jun 1, 2016
@afvincent I agree on all points. The docs should be updated and the negative behavior looks funny.
retagged this issue as 2.0 to conserve issues.
Negative shifts not working is an Agg bug, svg shifts to the right and there is no-shift in the pdf.
afvincent commented on Jun 2, 2016
About the documentation update, what about changing a bit the docstring of lines.Line2D.set_linewidth? For example by:
Alternatively a dash tuple of the following form can be provided:: (offset, onoffseq), where ``onoffseq`` is an even length tuple of on and off ink, in points if the line width is thiner than 1 pt, and in units of line width if it is larger.or
Alternatively a dash tuple of the following form can be provided:: (offset, onoffseq), where ``onoffseq`` is an even length tuple of on and off ink in points. If the line width is larger than 1 pt, the dash tuple is scaled with respect to the line width value (in pt).IMHO, the second one is more precise as the offset value is also scaled by the line width value (see ll. 865-874 in commit 04ffd42)
If one of the formulations is OK, I can submit a PR with this change. As think that some other docstrings will need to be updated as well (at least the ones of set_linestyle in collections.py and backend_bases.py)
afvincent commented on Jun 5, 2016
@tacaswell : Are you sure that the PDF backend is not working? Because if I simply do a plt.savefig("NiceName.<ext among {png, pdf, svg}>", dpi=100), I have the feeling that only the PNG export is not working. Here are the pictures I got (conversions from PDF and SVG into PNG were done with ImageMagick).



PNG:
PDF (-> PNG via ImageMagick):
SVG (-> PNG via ImageMagick):
PS: I generated the plots with Matplotlib 1.5.2rc2.post1938+g4ba20b8
(2016-06-06) Edit: I had forgotten to precise the type of the pictures... Corrected for the record.
tacaswell commented on Jun 5, 2016
Your right, I am was mistaken about pdf. It could have the viewer I was using?
afvincent commented on Jun 5, 2016
Not sure I understood your last remark. I just tested my PDF with Evince, xpdf, Inkscape (import), qpdfview and MuPDF (everything on Linux), and every viewer was fine. But isn't it the expected behavior and the PDF rationale?
PS : I don't know why but I can't upload on GitHub the PDF I produced in my previous answer. I get an error from GitHub (“Unfortunately, we don’t support that file type. Try again with a PNG, GIF, JPG, DOCX, PPTX, XLSX, TXT, PDF, or ZIP.”)
jkseppan commented on Jun 18, 2016
I think the pdf backend just writes the offset into the pdf file. The pdf specification doesn't seem to explicitly say that the offset must be nonnegative, but I think it is implied. Different viewers could handle it differently.
afvincent commented on Jun 18, 2016
Here is what I found about dash patterns
PDFReference_3rd_ed_pp.175-176_bis.pdf, and indeed the way “dash phase” pattern is handled seems to assume it's a positive quantity : if I understood correctly, a line starts to be drawn when accumulated sum of the patterns is equal to the offset.
A possibility to handle negative values might be to convert them into a equivalent positive value (% length of a complete dash pattern). Something like
afvincent commented on Jun 18, 2016
OK sorry, I've just seen that @jkseppan already commited a similar solution with 54450fd…
tacaswell commented on Jul 12, 2016
With the changes in #6710 for png
FIX: do dash scaling early
FIX: do dash scaling early