Skip to main content

graphics - Plot points shifted (a lot) in output and PNG export but not in PDF export


Bug introduced in 8 or earlier and fixed in 12.0.0





Consider the following code:


Needs["SciDraw`"]
Needs["PolygonPlotMarkers`"]
plotData = {{1, 0}};
markers[size_] := Graphics[{PolygonMarker["Disk", Offset[size]]}];
plotA = ListPlot[plotData, PlotMarkers -> markers[8]];
plot = Figure[FigurePanel[{FigGraphics[plotA]}], CanvasSize -> {3, 2}]

enter image description here



The plotted point is not where it's supposed to be, that is, at {1,0}. In fact, it is shifted by precisely {-0.5,0.5}. Only when exported to pdf (last panel) does the point appear at the right position.


What could be the reason for this behavior?


Note that both SciDraw and PolygonPlotMarkers seem to influence the result. At least I can't reproduce the phenomenon when not using both of those packages. However, independent of what those packages do, what could possibly lead to a different output in these two file formats?


If it matters, I have tested this using version 11.0.1 and version 10.4.1 on 64 bit Linux.


SciDraw is available from here.


PolygonPlotMarkers is available from here.



Answer



This issue has nothing to do with the PolygonPlotMarkers` package and appears with any primitive-based plot marker:


Needs["SciDraw`"]
plotData = {{1, 0}};

plotA = ListPlot[plotData, PlotMarkers -> Graphics[Disk[{0, 0}, Offset[3]]]]
plot = Figure[FigurePanel[{FigGraphics[plotA]}], CanvasSize -> {3, 2}]


output


output



After some digging I distilled the problem to the following:


g[size_] := Graphics[GeometricTransformation[{
Inset[Graphics[{Blue, Disk[{0, 0}, Offset[7]]}], {1, 0}],

Inset[Style["\[FilledCircle]", Red, FontSize -> 15], {1, 0}]},
{{216, 0}, {0, 144}}],
Frame -> True, PlotRange -> {{0, 216}, {0, 144}}, ImageSize -> size];

g /@ {150, 200, 300, 400}


screenshot



Here is how it looks Exported to PDF:



Export["i.pdf", %] // SystemOpen


screenshot



In the above we have the same affine transformation applied to two Insets: the first contains Graphics, the second contains a glyph. Both Insets have identical second arguments which specify where they will be placed in the enclosing graphics, hence one should expect that their positions will be identical as it takes place without applying GeometricTransformation:


Graphics[{
Inset[Graphics[{Blue, Disk[{0, 0}, Offset[7]]}], {1, 0}],
Inset[Style["\[FilledCircle]", Red, FontSize -> 15], {1, 0}]},
Frame -> True, PlotRange -> {{0, 1}, {0, 1}}]



graphics



So we have faced a bug in rendering of GeometricTransformation by the FrontEnd. I have found two workarounds:




  1. Specify explicit AlignmentPoint for Graphics:


    g[size_] := Graphics[GeometricTransformation[{
    Inset[Graphics[{Blue, Disk[{0, 0}, Offset[6]]}, AlignmentPoint -> {0, 0}], {1, 0}],

    Inset[Style["\[FilledCircle]", Red, FontSize -> 15], {1, 0}]},
    {{216, 0}, {0, 144}}],
    Frame -> True, PlotRange -> {{0, 216}, {0, 144}}, ImageSize -> size];

    g /@ {150, 200, 300, 400}


    screenshot






  2. Specify explicit third argument for Inset:


    g[size_] := Graphics[GeometricTransformation[{
    Inset[Graphics[{Blue, Disk[{0, 0}, Offset[6]]}], {1, 0}, {0, 0}],
    Inset[Style["\[FilledCircle]", Red, FontSize -> 15], {1, 0}]},
    {{216, 0}, {0, 144}}],
    Frame -> True, PlotRange -> {{0, 216}, {0, 144}}, ImageSize -> size];

    g /@ {150, 200, 300, 400}



    screenshot





For working with the SciDraw` package the first workaround is appropriate:


Needs["SciDraw`"]
plotData = {{1, 0}};
plotA = ListPlot[plotData,
PlotMarkers -> Graphics[{Blue, Disk[{0, 0}, Offset[5]]}, AlignmentPoint -> {0, 0}]];

plot = Figure[FigurePanel[{FigGraphics[plotA]}], CanvasSize -> {3, 2}]


output



I recommend reporting it to the creator of SciDraw` Mark A. Caprio and to Wolfram tech support. Since the usage of primitive-based plot markers is very common, this problem should be taken quite seriously.




UPDATE


It looks like this bug is strongly related to this, and the same workaround works:


Graphics[{GeometricTransformation[{

Inset[Graphics[{Blue, Disk[{0, 0}, Offset[7]]}], {100, 0}],
Inset[Style["\[FilledCircle]", Red, FontSize -> 15], {100, 0}]},
{{216, 0}, {0, 144}}/100]}, Frame -> True, PlotRange -> {{0, 216}, {0, 144}}]


graphics



(I multiplied the second argument of Inset by 100 and divided the transformation matrix by 100).


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...