Mathematica: растры в 3D графике - PullRequest
17 голосов
/ 10 июня 2011

Бывают случаи, когда экспорт в 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

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

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

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

enter image description here

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

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

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


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

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

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 = First@ImportString[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. Сверху - версия в формате eps с размером файла 614 КБ, снизу - версия в формате PDF с размером файла 455 КБ. Второй столбец показывает вывод, полученный из M8. Сверху - версия eps с размером файла 643 КБ, снизу - версия PDF с размером файла 463 КБ.

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

Ответы [ 6 ]

7 голосов
/ 10 июня 2011

Полное решение для 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 = First@ImportString[ExportString[axes, "PDF"], "PDF"];
(*Getting explicid ImageSize of graphics imported form PDF*)
imageSize = 
 Last@Transpose[{First@#, Last@#} & /@ 
    Sort /@ Transpose@
      First@Cases[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

3 голосов
/ 10 июня 2011

Просто проверяю (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

2 голосов
/ 08 ноября 2011

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

Вот код из раздела ОБНОВЛЕНИЕ вопроса (немного измененный):

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 = First@ImportString[ExportString[axes, "PDF"], "PDF"];

Остальной ответ -новое решение.

Сначала мы устанавливаем второй аргумент Raster, чтобы он заполнил полные PlotRange из 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 -> First@fig]
Export["C:/Result.pdf", result];

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

2 голосов
/ 09 октября 2011

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

Вот код из раздела ОБНОВЛЕНИЕ вопроса:

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]

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

ОБНОВЛЕНИЕ

Как 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]
0 голосов
/ 03 июля 2014

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

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

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

Код экспортирует графику в файл EPS, используя высококачественную растеризацию как 3D-контента, так и оси.Наконец, вы можете преобразовать 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"]];
0 голосов
/ 10 июня 2011

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...