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

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...

Is there a way to do conditional matrix loop using 'continue'

I have the following: n = 3; m = 5; ww = RandomReal[{0, 0.1}, {n, n}]; uu = RandomReal[{0, 1}, {m, n}]; pp = RandomReal[{0, 1}, {n, n}]; ss = RandomInteger[{0, 5}, {m, n}]; Grid[{{"ww", "uu", "pp", "ss"}, {ww // TableForm, uu // TableForm, pp // TableForm, ss // TableForm}}, Spacings -> {5, 2}, Dividers -> All] where I would like to look at every element of matrix ss and produce a matrix tt , with zeroes at the locations in ss which have zeroes, and in all other positions do the following: tt = (-1/Subscript[ww, m]) Log[(1 - uu)/(Subscript[pp, m - 1])], where Subscript[ww, m] is the value at index of ww matrix and where Subscript[pp, m - 1] is the value at index-1 of pp matrix. So for example if the first value ever read from matrix ss happens to be 2, then value taken from matrix ww would be from the row 2, but from pp would be from row 1. Also how to tell difference between a 0 as a valid value from within the matrix elemen...