Подтвердить что ты не робот

Mathematica: Растр в 3D-графике

Бывают случаи, когда экспортировать в pdf файл просто хлопотно. Если данные, которые вы рисуете, содержат много точек, то ваша фигура будет большой по размеру, и программа просмотра pdf по вашему выбору будет тратить большую часть времени на изображение высокого качества. Таким образом, мы можем экспортировать это изображение как jpeg, png или tiff. Изображение будет прекрасным с определенного вида, но когда вы увеличите масштаб изображения, он будет искажен. В какой-то степени это хорошо для фигуры, которую мы рисуем, но если ваше изображение содержит текст, то этот текст будет выглядеть неровным.

Чтобы попытаться получить лучшее из обоих миров, мы можем разделить эту фигуру на две части: оси с метками и трехмерное изображение. Таким образом, оси могут быть экспортированы в формате pdf или eps, а 3D-фигура - в растровый. Хотелось бы, чтобы я знал, как позже объединить два в Mathematica, поэтому на данный момент мы можем использовать редактор векторной графики, такой как Inkscape или Illustrator, чтобы объединить два.

Мне удалось добиться этого для сюжета, который я сделал в публикации, но это побуждает меня создавать подпрограммы в Mathematica, чтобы автоматизировать этот процесс. Вот что я до сих пор:

SetDirectory[NotebookDirectory[]];
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];

Мне нравится запускать свой ноутбук, установив рабочий каталог в каталог ноутбука. Поскольку я хочу, чтобы мои изображения имели размер, который я указываю, я задал рабочую среду стиля печати, посмотрите this для получения дополнительной информации.

in = 72;
G3D = Graphics3D[
  AlignmentPoint -> Center,
  AspectRatio -> 0.925,
  Axes -> {True, True, True},
  AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}},
  AxesStyle -> Directive[10, Black],
  BaseStyle -> {FontFamily -> "Arial", FontSize -> 12},
  Boxed -> False,
  BoxRatios -> {3, 3, 1},
  LabelStyle -> Directive[Black],
  ImagePadding -> All,
  ImageSize -> 5 in,
  PlotRange -> All,
  PlotRangePadding -> None,
  TicksStyle -> Directive[10],
  ViewPoint -> {2, -2, 2},
  ViewVertical -> {0, 0, 1}
 ]

Здесь мы устанавливаем вид сюжета, который хотим сделать. Теперь давайте создадим наш сюжет.

g = Show[
  Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, 
   Mesh -> None,
   AxesLabel -> {"x", "y", "z"}
   ], 
  Options[G3D]
 ]

enter image description here

Теперь нам нужно найти способ разделения. Давайте начнем с рисования осей.

axes = Graphics3D[{}, AbsoluteOptions[g]]

enter image description here

fig = Show[g, 
  AxesStyle -> Directive[Opacity[0]],
  FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}
 ]

enter image description here

Я включил facegrids, чтобы мы могли сопоставить фигуру с осью в процессе редактирования сообщения. Теперь мы экспортируем оба изображения.

Export["Axes.pdf", axes];
Export["Fig.pdf", Rasterize[fig, ImageResolution -> 300]];

Вы получите два pdf файла, которые вы можете редактировать и объединить в pdf или eps. Хотелось бы, чтобы все было так просто, но это не так. Если вы действительно это сделали, вы получите следующее:

enter image description here

Две цифры имеют разные размеры. Я знаю axes.pdf правильно, потому что, когда я открываю его в Inkspace, размер фигуры составляет 5 дюймов, как я уже указывал ранее.

Я уже упоминал, что мне удалось получить это с одним из моих сюжетов. Я очищу файл и изменю графики, чтобы сделать его более доступным для тех, кто хочет видеть, что это на самом деле правда. В любом случае, кто-нибудь знает, почему я не могу получить два файла PDF одинакового размера? Кроме того, имейте в виду, что мы хотим получить красивый сюжет для Растрированной фигуры. Спасибо за ваше время.

PS. В качестве бонуса мы можем избежать редактирования сообщений и просто объединить две фигуры в математике? Растрированная версия и версия векторной графики.


EDIT:

Спасибо rcollyer за его комментарий. Я публикую результаты его комментария.

Следует отметить, что когда мы экспортируем оси, нам нужно установить Background на None, чтобы мы могли иметь прозрачное изображение.

Export["Axes.pdf", axes, Background -> None];
Export["Fig.pdf", Rasterize[fig, ImageResolution -> 300]];
a = Import["Axes.pdf"];
b = Import["Fig.pdf"];
Show[b, a]

enter image description here

И затем, экспорт фигуры дает желаемый эффект

Export["FinalFig.pdf", Show[b, a]]

enter image description here

Оси сохраняют красивые компоненты векторной графики, а фигура теперь представляет собой растеризованную версию того, что мы нарисовали. Но главный вопрос остается. Как вы сопоставляете две цифры?

UPDATE:

На мой вопрос ответил Алексей Попков. Я хотел бы поблагодарить его за то, что уделил время изучению моей проблемы. Следующий код является примером для тех из вас, кто хочет использовать технику, о которой я упоминал ранее. Обратитесь к Алексею Попкову за полезные комментарии в его коде. Ему удалось заставить его работать в Mathematica 7, и он работает еще лучше в Mathematica 8. Вот результат:

SetDirectory[NotebookDirectory[]];
SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
$HistoryLength = 0;
in = 72;
G3D = Graphics3D[
 AlignmentPoint -> Center, AspectRatio -> 0.925, Axes -> {True, True, True},
 AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, AxesStyle -> Directive[10, Black],
 BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, Boxed -> False, 
 BoxRatios -> {3, 3, 1}, LabelStyle -> Directive[Black], ImagePadding -> 40,
 ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> 0,
 TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, ViewVertical -> {0, 0, 1}
];
axesLabels = Graphics3D[{
 Text[Style["x axis (units)", Black, 12], Scaled[{.5, -.1, 0}], {0, 0}, {1, -.9}],
 Text[Style["y axis (units)", Black, 12], Scaled[{1.1, .5, 0}], {0, 0}, {1, .9}],
 Text[Style["z axis (units)", Black, 12], Scaled[{0, -.15, .7}], {0, 0}, {-.1, 1.5}]
}];
fig = Show[
  Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None],
  ImagePadding -> {{40, 0}, {15, 0}}, Options[G3D]
];
axes = Show[
  Graphics3D[{}, FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}, 
    AbsoluteOptions[fig]], axesLabels, 
    Epilog -> Text[Style["Panel A", Bold, Black, 12], ImageScaled[{0.075, 0.975}]]
];
fig = Show[fig, AxesStyle -> Directive[Opacity[0]]];
Row[{fig, axes}]

На этом этапе вы должны увидеть следующее:

enter image description here

Увеличение зависит от разрешения вашего изображения. Вы должны попробовать разные значения, чтобы увидеть, как это изменит ваше изображение.

fig = Magnify[fig, 5];
fig = Rasterize[fig, Background -> None];

Совместите графику

axes = [email protected][ExportString[axes, "PDF"], "PDF"];
result = Show[axes, Epilog -> Inset[fig, {0, 0}, {0, 0}, ImageDimensions[axes]]];

Экспортировать их

Export["Result.pdf", result];
Export["Result.eps", result];

Единственное различие, которое я обнаружил между M7 и M8 с использованием вышеуказанного кода, заключается в том, что M7 не экспортирует eps файл правильно. Кроме того, сейчас все работает нормально.:)

enter image description here

В первом столбце показан результат, полученный из M7. Top - это версия eps с размером файла 614 kb, нижняя версия - pdf-версия с размером файла 455 kb. Во втором столбце показан результат, полученный от M8. Вершиной является версия eps с размером файла 643 kb, нижняя версия - pdf-версия с размером файла 463 kb.

Надеюсь, вы сочтете это полезным. Ответьте Alexey, чтобы увидеть комментарии в его коде, они помогут вам избежать ошибок с Mathematica.

4b9b3361

Ответ 1

Полное решение для Mathematica 7.0.1: исправление ошибок

Код с комментариями:

(*controls the resolution of rasterized graphics*)
magnification = 5;

SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"]
(*Turn off history for saving memory*)
$HistoryLength = 0;
(*Epilog will give us the bounding box of the graphics*)
g1 = Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, 
   AlignmentPoint -> Center, AspectRatio -> 0.925, 
   Axes -> {True, True, True}, 
   AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, 
   BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, 
   Boxed -> False, BoxRatios -> {3, 3, 1}, 
   LabelStyle -> Directive[Black], ImagePadding -> All, 
   ImageSize -> 5*72, PlotRange -> All, PlotRangePadding -> None, 
   TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, 
   ViewVertical -> {0, 0, 1}, AxesStyle -> Directive[Opacity[0]], 
   FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}, Mesh -> None, 
   ImagePadding -> 40, 
   Epilog -> {Red, AbsoluteThickness[1], 
     Line[{ImageScaled[{0, 0}], ImageScaled[{0, 1}], 
       ImageScaled[{1, 1}], ImageScaled[{1, 0}], 
       ImageScaled[{0, 0}]}]}];
(*The options list should NOT contain ImagePadding->Full.Even it is \
before ImagePadding->40 it is not replaced by the latter-another bug!*)
axes = Graphics3D[{Opacity[0], 
    Point[PlotRange /. AbsoluteOptions[g1] // Transpose]}, 
   AlignmentPoint -> Center, AspectRatio -> 0.925, 
   Axes -> {True, True, True}, 
   AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, 
   AxesStyle -> Directive[10, Black], 
   BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, 
   Boxed -> False, BoxRatios -> {3, 3, 1}, 
   LabelStyle -> Directive[Black], ImageSize -> 5*72, 
   PlotRange -> All, PlotRangePadding -> None, 
   TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, 
   ViewVertical -> {0, 0, 1}, ImagePadding -> 40, 
   Epilog -> {Red, AbsoluteThickness[1], 
     Line[{ImageScaled[{0, 0}], ImageScaled[{0, 1}], 
       ImageScaled[{1, 1}], ImageScaled[{1, 0}], 
       ImageScaled[{0, 0}]}]}];
(*fixing bug with ImagePadding loosed when specifyed as option in \
Plot3D*)
g1 = AppendTo[g1, ImagePadding -> 40];
(*Increasing ImageSize without damage.Explicit setting for \
ImagePadding is important (due to a bug in behavior of \
ImagePadding->Full)!*)
g1 = Magnify[g1, magnification];
g2 = Rasterize[g1, Background -> None];
(*Fixing bug with non-working option Background->None when graphics \
is Magnifyed*)
g2 = g2 /. {255, 255, 255, 255} -> {0, 0, 0, 0};
(*Fixing bug with icorrect exporting of Ticks in PDF when Graphics3D \
and 2D Raster are combined*)
axes = [email protected][ExportString[axes, "PDF"], "PDF"];
(*Getting explicid ImageSize of graphics imported form PDF*)
imageSize = 
 [email protected][{[email protected]#, [email protected]#} & /@ 
    Sort /@ [email protected]
      [email protected][axes, 
        Style[{Line[x_]}, ___, RGBColor[1.`, 0.`, 0.`, 1.`], ___] :> 
         x, Infinity]]
(*combining Graphics3D and Graphics*)
result = Show[axes, Epilog -> Inset[g2, {0, 0}, {0, 0}, imageSize]]
Export["C:\\result.pdf", result]

Вот что я вижу в ноутбуке:

screenshot

И вот что я получаю в PDF:

screenshot

Ответ 2

Просто проверка (Mma8):

SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
in = 72;
G3D = Graphics3D[AlignmentPoint -> Center, AspectRatio -> 0.925, 
   Axes -> {True, True, True}, 
   AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, 
   AxesStyle -> Directive[10, Black], 
   BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, 
   Boxed -> False, BoxRatios -> {3, 3, 1}, 
   LabelStyle -> Directive[Black], ImagePadding -> All, 
   ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> None, 
   TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, 
   ViewVertical -> {0, 0, 1}];
g = Show[Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None, 
    AxesLabel -> {"x", "y", "z"}], Options[G3D]];
axes = Graphics3D[{}, AbsoluteOptions[g]];
fig = Show[g, AxesStyle -> Directive[Opacity[0]], 
   FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}];
Export["c:\\Axes.pdf", axes, Background -> None];
Export["c:\\Fig.pdf", Rasterize[fig, ImageResolution -> 300]];
a = Import["c:\\Axes.pdf"];
b = Import["c:\\Fig.pdf"];
Export["c:\\FinalFig.pdf", Show[b, a]]

enter image description here

Ответ 3

В Mathematica 8 проблема может быть решена еще проще с использованием новой функции Overlay.

Вот код из раздела UPDATE вопроса:

SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
$HistoryLength = 0;
in = 72;
G3D = Graphics3D[AlignmentPoint -> Center, AspectRatio -> 0.925, 
   Axes -> {True, True, True}, 
   AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, 
   AxesStyle -> Directive[10, Black], 
   BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, 
   Boxed -> False, BoxRatios -> {3, 3, 1}, 
   LabelStyle -> Directive[Black], ImagePadding -> 40, 
   ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> 0, 
   TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, 
   ViewVertical -> {0, 0, 1}];
axesLabels = 
  Graphics3D[{Text[Style["x axis (units)", Black, 12], 
     Scaled[{.5, -.1, 0}], {0, 0}, {1, -.9}], 
    Text[Style["y axis (units)", Black, 12], 
     Scaled[{1.1, .5, 0}], {0, 0}, {1, .9}], 
    Text[Style["z axis (units)", Black, 12], 
     Scaled[{0, -.15, .7}], {0, 0}, {-.1, 1.5}]}];
fig = Show[Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None], 
   ImagePadding -> {{40, 0}, {15, 0}}, Options[G3D]];
axes = Show[
   Graphics3D[{}, FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}, 
    AbsoluteOptions[fig]], axesLabels, 
   Epilog -> 
    Text[Style["Panel A", Bold, Black, 12], 
     ImageScaled[{0.075, 0.975}]]];
fig = Show[fig, AxesStyle -> Directive[Opacity[0]]];

И вот решение:

gr = Overlay[{axes, 
   Rasterize[fig, Background -> None, ImageResolution -> 300]}]
Export["Result.pdf", gr]

В этом случае нам не нужно преобразовывать шрифты в контуры.

UPDATE

Как отметил jmlopez в комментариях к этому ответу, опция Background -> None не работает должным образом в Mac OS X в Mathematica 8.0.1. Одним из способов решения проблемы является замена белых непрозрачных точек прозрачным:

gr = Overlay[{axes, 
   Rasterize[fig, Background -> None, 
     ImageResolution -> 300] /. {255, 255, 255, 255} -> {0, 0, 0, 0}}]
Export["Result.pdf", gr]

Ответ 4

Здесь я представляю другую версию исходного решения, которая использует второй аргумент Raster вместо Inset. Я думаю, что этот способ немного более прост.

Вот код из раздела UPDATE вопроса (немного измененный):

SetOptions[$FrontEnd, PrintingStyleEnvironment -> "Working"];
$HistoryLength = 0;
in = 72;
G3D = Graphics3D[AlignmentPoint -> Center, AspectRatio -> 0.925, 
   Axes -> {True, True, True}, 
   AxesEdge -> {{-1, -1}, {1, -1}, {-1, -1}}, 
   AxesStyle -> Directive[10, Black], 
   BaseStyle -> {FontFamily -> "Arial", FontSize -> 12}, 
   Boxed -> False, BoxRatios -> {3, 3, 1}, 
   LabelStyle -> Directive[Black], ImagePadding -> 40, 
   ImageSize -> 5 in, PlotRange -> All, PlotRangePadding -> 0, 
   TicksStyle -> Directive[10], ViewPoint -> {2, -2, 2}, 
   ViewVertical -> {0, 0, 1}];
axesLabels = 
  Graphics3D[{Text[Style["x axis (units)", Black, 12], 
     Scaled[{.5, -.1, 0}], {0, 0}, {1, -.9}], 
    Text[Style["y axis (units)", Black, 12], 
     Scaled[{1.1, .5, 0}], {0, 0}, {1, .9}], 
    Text[Style["z axis (units)", Black, 12], 
     Scaled[{0, -.15, .7}], {0, 0}, {-.1, 1.5}]}];
fig = Show[Plot3D[Sin[x y], {x, 0, Pi}, {y, 0, Pi}, Mesh -> None], 
   ImagePadding -> {{40, 0}, {15, 0}}, Options[G3D]];
axes = Show[
   Graphics3D[{}, FaceGrids -> {{-1, 0, 0}, {0, 1, 0}}, 
    AbsoluteOptions[fig]], axesLabels, 
   Prolog -> 
    Text[Style["Panel A", Bold, Black, 12], 
     ImageScaled[{0.075, 0.975}]]];
fig = Show[fig, AxesStyle -> Directive[Opacity[0]]];
fig = Magnify[fig, 5];
fig = Rasterize[fig, Background -> None];
axes2D = [email protected][ExportString[axes, "PDF"], "PDF"];

Остальная часть ответа - это новое решение.

Сначала мы устанавливаем второй аргумент Raster, чтобы он заполнил полный PlotRange of axes2D. Общий способ сделать это:

fig = fig /. 
   Raster[data_, rectangle_, opts___] :> 
    Raster[data, {Scaled[{0, 0}], Scaled[{1, 1}]}, opts];

Другой способ - сделать прямое присвоение соответствующему Part исходного выражения:

fig[[1, 2]] = {Scaled[{0, 0}], Scaled[{1, 1}]}

Обратите внимание, что этот последний код основан на знании внутренней структуры выражения, сгенерированного Rasterize, которое потенциально зависит от версии.

Теперь мы объединяем два графических объекта очень просто:

result = Show[axes2D, fig]

И экспортируйте результат:

Export["C:/Result.pdf", result];
Export["C:/Result.eps", result];

Оба .eps и .pdf экспортируются отлично с Mathematica 8.0.4 под Windows XP 32 бит и выглядят идентично файлам, экспортированным с исходным кодом:

result = Show[axes2D, 
  Epilog -> Inset[fig, Center, Center, ImageScaled[{1, 1}]]]
Export["C:/Result.pdf", result];
Export["C:/Result.eps", result];

Обратите внимание, что нам необязательно преобразовывать axes в контуры, по крайней мере, при экспорте в PDF. Код

result = Show[axes, 
  Epilog -> Inset[fig, Center, Center, ImageScaled[{1, 1}]]]
Export["C:/Result.pdf", result];

и код

fig[[1, 2]] = {ImageScaled[{0, 0}], ImageScaled[{1, 1}]};
result = Show[axes, Epilog -> [email protected]]
Export["C:/Result.pdf", result];

создают файлы PDF, похожие на обе предыдущие версии.

Ответ 5

Это похоже на много шума из ничего. Когда я его прочитал, проблема, которую вы хотите решить, следующая:

  • Вы хотите экспортировать в векторном формате, чтобы при печати оптимальное разрешение использовалось для шрифтов, линий и графики.
  • В вашей программе редактирования вам не нужно беспокоиться о медлительности рендеринга сложного векторного рисунка.

Эти требования могут быть выполнены путем экспорта в формате .eps и использования встроенного растрированного изображения предварительного просмотра.

Export["file.eps","PreviewFormat"->"TIFF"]

Это будет работать во многих приложениях. К сожалению, фильтр MS Word eps сильно изменился в последних четырех версиях или около того, и хотя он работал у меня в одной из старых функций, он больше не работает в W2010. Я слышал слухи, что он может работать в версии для Mac, но я не могу проверить прямо сейчас.

Ответ 6

Mathematica 9.0.1.0/64-bit Linux: В общем, кажется, очень сложно разместить векторизованные оси в правильном положении. В большинстве приложений достаточно просто растеризовать все с высоким разрешением:

fig = Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3}, Mesh -> None];

Export["export.eps", fig, "AllowRasterization" -> True, 
  ImageResolution -> 600];

Код экспортирует графику в EPS файл, используя высококачественную растеризацию как трехмерного контента, так и оси. Наконец, вы можете преобразовать EPS файл в PDF, используя, например, команду Linux epspdf:

epspdf export.eps

Это, вероятно, достаточно для большинства пользователей, и это экономит вам много времени. Однако, если вы действительно хотите экспортировать текст в виде векторной графики, вы можете попробовать следующую функцию:

ExportAsSemiRaster[filename_, dpi_, fig_, plotrange_, 
   plotrangepadding_] := (
   range = 
    Show[fig, PlotRange -> plotrange, 
     PlotRangePadding -> plotrangepadding];
   axes = Show[Graphics3D[{}, AbsoluteOptions[range]]];
   noaxes = Show[range, AxesStyle -> Transparent];
   raster = 
    Rasterize[noaxes, Background -> None, ImageResolution -> dpi];
   result = 
    Show[raster, 
     Epilog -> Inset[axes, Center, Center, ImageDimensions[raster]]];
   Export[filename, result];
   );

Вам нужно явно указать PlotRange и PlotRangePadding. Пример:

fig = Graphics3D[{Opacity[0.9], Orange, 
    Polygon[{{0, 0, 0}, {4, 0, 4}, {4, 5, 7}, {0, 5, 5}}], 
    Opacity[0.05], Gray, CuboidBox[{0, 0, 0}, {4, 5, 7}]}, 
   Axes -> True, AxesStyle -> Darker[Orange], 
   AxesLabel -> {"x1", "x2", "x3"}, Boxed -> False, 
   ViewPoint -> {-8.5, -8, 6}];
ExportAsSemiRaster["export.pdf", 600, 
  fig, {{0, 4}, {0, 5}, {0, 7}}, {.0, .0, .0}];
Print[Import["export.pdf"]];