Графики в стиле xkcd в MATLAB

225

граф в стиле xkcd

Так талантливые люди уже поняли, как создавать графики в стиле xkcd в Mathematica , в LaTeX , в Python и в R уже.

Как можно использовать MATLAB для создания сюжета, похожего на приведенный выше?

Что я пробовал

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

 annotation('textbox',[left+left/8 top+0.65*top 0.05525 0.065],...
'String',{'EMBARRASSMENT'},...
'FontSize',24,...
'FontName','Humor',...
'FitBoxToText','off',...
'LineStyle','none');

Для волнистой линии я экспериментировал с добавлением небольшого случайного шума и сглаживанием:

 smooth(0.05*randn(size(x)),10)

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

бла
источник
9
Редактировать, кажется, удовлетворяет «сначала какие-то фундаментальные исследования». Кроме того, ответы здесь хорошие. Повторное открытие.
Shog9

Ответы:

118

Я вижу два способа решить эту проблему: Первый способ - добавить немного дрожания к координатам x / y объектов графика. Преимущество этого в том, что вы можете легко изменить график, но вы должны нарисовать оси самостоятельно, если вы хотите, чтобы они были xkcdyfied (см. Решение @Rody Oldenhuis ). Второй способ - создать не дрожащий график и использовать его imtransformдля применения случайного искажения к изображению. Это имеет то преимущество, что вы можете использовать его с любым графиком, но в итоге вы получите изображение, а не редактируемый график.

Сначала я покажу # 2, а мою попытку # 1 ниже (если вам нравится # 1 лучше, посмотрите на решение Роди !).

введите описание изображения здесь

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

%# define plot data
x = 1:0.1:10;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^2/2) + 1;

%# plot
fh = figure('color','w');
hold on
plot(x,y1,'b','lineWidth',3);
plot(x,y2,'w','lineWidth',7);
plot(x,y2,'r','lineWidth',3);

xlim([0.95 10])
ylim([0 5])
set(gca,'fontName','Comic Sans MS','fontSize',18,'lineWidth',3,'box','off')

%# add an annotation 
 annotation(fh,'textarrow',[0.4 0.55],[0.8 0.65],...
     'string',sprintf('text%shere',char(10)),'headStyle','none','lineWidth',1.5,...
     'fontName','Comic Sans MS','fontSize',14,'verticalAlignment','middle','horizontalAlignment','left')

%# capture with export_fig
im = export_fig('-nocrop',fh);

%# add a bit of border to avoid black edges
im = padarray(im,[15 15 0],255);

%# make distortion grid
sfc = size(im);
[yy,xx]=ndgrid(1:7:sfc(1),1:7:sfc(2));
pts = [xx(:),yy(:)];
tf = cp2tform(pts+randn(size(pts)),pts,'lwm',12);
w = warning;
warning off images:inv_lwm:cannotEvaluateTransfAtSomeOutputLocations
imt = imtransform(im,tf);
warning(w)

%# remove padding
imt = imt(16:end-15,16:end-15,:);

figure('color','w')
imshow(imt)

Вот моя первая попытка дрожания

введите описание изображения здесь

%# define plot data
x = 1:0.1:10;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^2/2) + 1;

%# jitter
x = x+randn(size(x))*0.01;
y1 = y1+randn(size(x))*0.01;
y2 = y2+randn(size(x))*0.01;

%# plot
figure('color','w')
hold on
plot(x,y1,'b','lineWidth',3);
plot(x,y2,'w','lineWidth',7);
plot(x,y2,'r','lineWidth',3);

xlim([0.95 10])
ylim([0 5])
set(gca,'fontName','Comic Sans MS','fontSize',18,'lineWidth',3,'box','off')
Jonas
источник
4
Наслаждайтесь своим временем на SO, пока вы можете! ;)
gnovice
2
@gnovice: Это будет мой третий. Надеюсь, я уже понял это в значительной степени :)
Джонас
@Jonas хорошая работа! Я думаю, что ваш # 2 получил правильное чувство покачивания, среди всех решений до сих пор. Тем не менее, он по-прежнему пропускает большие волнистые галочки, рамку вокруг текста и нарисованные от руки изогнутые линии, чтобы указывать от текста на линию ...
бла
2
+1 за EXPORT_FIG. Превращение всех моих графиков более приятным благодаря сглаживанию.
Яманеко
1
@JasonS: извините, это было самое близкое, что у меня было в то время.
Джонас
92

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

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

Примеры

участок Введите описание изображения здесь

Бар и участок

Введите описание изображения здесь

Коробка и участок Введите описание изображения здесь

Как это устроено

Функция работает путем перебора дочерних элементов осей. Если дети имеют тип lineили patchэто немного искажает их. Если дочерний тип имеет тип, hggroupон перебирает дочерние элементы hggroup. У меня есть планы по поддержке других типов графиков, таких как image, но не ясно, как лучше искажать изображение, чтобы иметь стиль xkcd.

Наконец, чтобы убедиться, что искажения выглядят равномерно (то есть короткие линии не искажаются больше, чем длинные линии), я измеряю длину линии в пикселях, а затем увеличиваю выборку пропорционально ее длине. Затем я добавляю шум к каждому N-му семплу, который производит линии с более или менее одинаковым искажением.

Код

Вместо того, чтобы вставлять несколько сотен строк кода, я просто сошлюсь на суть источника . Кроме того, исходный код и код для генерации приведенных выше примеров находятся в свободном доступе GitHub .

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

Слейтон
источник
4
Ницца! Я работал с подобным фрагментом кода, который реализует export_figмаршрут, то есть сначала форматирует сюжет, похожий на xkcd, а затем искажает картинку.
Джонас
4
Спасибо. Я действительно горжусь участками. Я был удивлен уровнем взлома, необходимого для того, чтобы показать эти сюжеты.
Слейтон
Я буду использовать его для преобразования всей презентации в стиль XKCD.
Яманеко
Привет Слейтон, это фантастика! У меня только один вопрос, есть ли способ также сделать оси Cartoony / XKCD-иш? Это сделало бы это для меня, и я был бы в состоянии использовать это! :-) Большое спасибо ...
Spacey
@Learnaholic AFAIK matlab не предоставляет никаких API (документированных или недокументированных) для изменения способа визуализации осей
Slayton
63

Первый шаг ... найдите системный шрифт, который вам нравится (используйте функцию, listfontsчтобы увидеть, что доступно) или установите тот, который соответствует стилю рукописного ввода из xkcd . Я нашел шрифт TrueType "Humor Sans" от пользователя ch00f, упомянутый в этом сообщении в блоге , и буду использовать его для моих последующих примеров.

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

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

xkcd_axes.m:

function hAxes = xkcd_axes(xkcdOptions, varargin)

  hAxes = axes(varargin{:}, 'NextPlot', 'add', 'Visible', 'off', ...
               'XLimMode', 'manual', 'YLimMode', 'manual');

  axesUnits = get(hAxes, 'Units');
  set(hAxes, 'Units', 'pixels');
  axesPos = get(hAxes, 'Position');
  set(hAxes, 'Units', axesUnits);
  xPoints = round(axesPos(3)/10);
  yPoints = round(axesPos(4)/10);
  limits = [xlim(hAxes) ylim(hAxes)];
  ranges = [abs(limits(2) - limits(1)) abs(limits(4) - limits(3))];
  backColor = get(get(hAxes, 'Parent'), 'Color');
  xColor = get(hAxes, 'XColor');
  yColor = get(hAxes, 'YColor');
  line('Parent', hAxes, 'Color', xColor, 'LineWidth', 3, ...
       'Clipping', 'off', ...
       'XData', linspace(limits(1), limits(2), xPoints), ...
       'YData', limits(3) + rand(1, xPoints).*0.005.*ranges(2));
  line('Parent', hAxes, 'Color', yColor, 'LineWidth', 3, ...
       'Clipping', 'off', ...
       'YData', linspace(limits(3), limits(4), yPoints), ...
       'XData', limits(1) + rand(1, yPoints).*0.005.*ranges(1));

  xTicks = get(hAxes, 'XTick');
  if ~isempty(xTicks)
    yOffset = limits(3) - 0.05.*ranges(2);
    tickIndex = true(size(xTicks));
    if ismember('left', xkcdOptions)
      tickIndex(1) = false;
      xkcd_arrow('left', [limits(1) + 0.02.*ranges(1) xTicks(1)], ...
                 yOffset, xColor);
    end
    if ismember('right', xkcdOptions)
      tickIndex(end) = false;
      xkcd_arrow('right', [xTicks(end) limits(2) - 0.02.*ranges(1)], ...
                 yOffset, xColor);
    end
    plot([1; 1]*xTicks(tickIndex), ...
         0.5.*[-yOffset; yOffset]*ones(1, sum(tickIndex)), ...
         'Parent', hAxes, 'Color', xColor, 'LineWidth', 3, ...
         'Clipping', 'off');
    xLabels = cellstr(get(hAxes, 'XTickLabel'));
    for iLabel = 1:numel(xLabels)
      xkcd_text(xTicks(iLabel), yOffset, xLabels{iLabel}, ...
                'HorizontalAlignment', 'center', ...
                'VerticalAlignment', 'middle', ...
                'BackgroundColor', backColor);
    end
  end

  yTicks = get(hAxes, 'YTick');
  if ~isempty(yTicks)
    xOffset = limits(1) - 0.05.*ranges(1);
    tickIndex = true(size(yTicks));
    if ismember('down', xkcdOptions)
      tickIndex(1) = false;
      xkcd_arrow('down', xOffset, ...
                 [limits(3) + 0.02.*ranges(2) yTicks(1)], yColor);
    end
    if ismember('up', xkcdOptions)
      tickIndex(end) = false;
      xkcd_arrow('up', xOffset, ...
                 [yTicks(end) limits(4) - 0.02.*ranges(2)], yColor);
    end
    plot(0.5.*[-xOffset; xOffset]*ones(1, sum(tickIndex)), ...
         [1; 1]*yTicks(tickIndex), ...
         'Parent', hAxes, 'Color', yColor, 'LineWidth', 3, ...
         'Clipping', 'off');
    yLabels = cellstr(get(hAxes, 'YTickLabel'));
    for iLabel = 1:numel(yLabels)
      xkcd_text(xOffset, yTicks(iLabel), yLabels{iLabel}, ...
                'HorizontalAlignment', 'right', ...
                'VerticalAlignment', 'middle', ...
                'BackgroundColor', backColor);
    end
  end

  function xkcd_arrow(arrowType, xArrow, yArrow, arrowColor)
    if ismember(arrowType, {'left', 'right'})
      xLine = linspace(xArrow(1), xArrow(2), 10);
      yLine = yArrow + rand(1, 10).*0.003.*ranges(2);
      arrowScale = 0.05.*ranges(1);
      if strcmp(arrowType, 'left')
        xArrow = xLine(1) + arrowScale.*[0 0.5 1 1 1 0.5];
        yArrow = yLine(1) + arrowScale.*[0 0.125 0.25 0 -0.25 -0.125];
      else
        xArrow = xLine(end) - arrowScale.*[0 0.5 1 1 1 0.5];
        yArrow = yLine(end) + arrowScale.*[0 -0.125 -0.25 0 0.25 0.125];
      end
    else
      xLine = xArrow + rand(1, 10).*0.003.*ranges(1);
      yLine = linspace(yArrow(1), yArrow(2), 10);
      arrowScale = 0.05.*ranges(2);
      if strcmp(arrowType, 'down')
        xArrow = xLine(1) + arrowScale.*[0 0.125 0.25 0 -0.25 -0.125];
        yArrow = yLine(1) + arrowScale.*[0 0.5 1 1 1 0.5];
      else
        xArrow = xLine(end) + arrowScale.*[0 -0.125 -0.25 0 0.25 0.125];
        yArrow = yLine(end) - arrowScale.*[0 0.5 1 1 1 0.5];
      end
    end
    line('Parent', hAxes, 'Color', arrowColor, 'LineWidth', 3, ...
         'Clipping', 'off', 'XData', xLine, 'YData', yLine);
    patch('Parent', hAxes, 'FaceColor', arrowColor, ...
          'EdgeColor', arrowColor, 'LineWidth', 2, 'Clipping', 'off', ...
          'XData', xArrow + [0 rand(1, 5).*0.002.*ranges(1)], ...
          'YData', yArrow + [0 rand(1, 5).*0.002.*ranges(2)]);
  end

end

xkcd_text.m:

function hText = xkcd_text(varargin)

  hText = text(varargin{:});
  set(hText, 'FontName', 'Humor Sans', 'FontSize', 13, ...
      'FontWeight', 'normal');

  backColor = get(hText, 'BackgroundColor');
  edgeColor = get(hText, 'EdgeColor');
  if ~strcmp(backColor, 'none') || ~strcmp(edgeColor, 'none')
    hParent = get(hText, 'Parent');
    extent = get(hText, 'Extent');
    nLines = size(get(hText, 'String'), 1);
    extent = extent + [-0.5 -0.5 1 1].*0.25.*extent(4)./nLines;
    yPoints = 5*nLines;
    xPoints = round(yPoints*extent(3)/extent(4));
    noiseScale = 0.05*extent(4)/nLines;
    set(hText, 'BackgroundColor', 'none', 'EdgeColor', 'none');
    xBox = [linspace(extent(1), extent(1) + extent(3), xPoints) ...
            extent(1) + extent(3) + noiseScale.*rand(1, yPoints) ...
            linspace(extent(1) + extent(3), extent(1), xPoints) ...
            extent(1) + noiseScale.*rand(1, yPoints)];
    yBox = [extent(2) + noiseScale.*rand(1, xPoints) ...
            linspace(extent(2), extent(2) + extent(4), yPoints) ...
            extent(2) + extent(4) + noiseScale.*rand(1, xPoints) ...
            linspace(extent(2) + extent(4), extent(2), yPoints)];
    patch('Parent', hParent, 'FaceColor', backColor, ...
          'EdgeColor', edgeColor, 'LineWidth', 2, 'Clipping', 'off', ...
          'XData', xBox, 'YData', yBox);
    hKids = get(hParent, 'Children');
    set(hParent, 'Children', [hText; hKids(hKids ~= hText)]);
  end

end

xkcd_line.m:

function hLine = xkcd_line(xData, yData, varargin)

  yData = yData + 0.01.*max(range(xData), range(yData)).*rand(size(yData));
  line(xData, yData, varargin{:}, 'Color', 'w', 'LineWidth', 8);
  hLine = line(xData, yData, varargin{:}, 'LineWidth', 3);

end

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

xS = [0.0359 0.0709 0.1004 0.1225 0.1501 0.1759 0.2219 0.2477 0.2974 0.3269 0.3582 0.3895 0.4061 0.4337 0.4558 0.4797 0.5074 0.5276 0.5589 0.5810 0.6013 0.6179 0.6271 0.6344 0.6381 0.6418 0.6529 0.6713 0.6842 0.6934 0.7026 0.7118 0.7265 0.7376 0.7560 0.7726 0.7836 0.7965 0.8149 0.8370 0.8573 0.8867 0.9033 0.9346 0.9659 0.9843 0.9936];
yS = [0.2493 0.2520 0.2548 0.2548 0.2602 0.2629 0.2629 0.2657 0.2793 0.2657 0.2575 0.2575 0.2602 0.2629 0.2657 0.2766 0.2793 0.2875 0.3202 0.3856 0.4619 0.5490 0.6771 0.7670 0.7970 0.8270 0.8433 0.8433 0.8243 0.7180 0.6199 0.5272 0.4510 0.4128 0.3392 0.2711 0.2275 0.1757 0.1485 0.1131 0.1022 0.0858 0.0858 0.1022 0.1267 0.1567 0.1594];

xF = [0.0304 0.0488 0.0727 0.0967 0.1335 0.1630 0.2090 0.2348 0.2698 0.3011 0.3269 0.3545 0.3803 0.4153 0.4466 0.4724 0.4945 0.5110 0.5350 0.5516 0.5608 0.5700 0.5755 0.5810 0.5884 0.6013 0.6179 0.6363 0.6492 0.6584 0.6676 0.6731 0.6842 0.6860 0.6934 0.7007 0.7136 0.7265 0.7394 0.7560 0.7726 0.7818 0.8057 0.8444 0.8794 0.9107 0.9475 0.9751 0.9917];
yF = [0.0804 0.0940 0.0967 0.1049 0.1185 0.1458 0.1512 0.1540 0.1649 0.1812 0.1812 0.1703 0.1621 0.1594 0.1703 0.1975 0.2411 0.3065 0.3801 0.4782 0.5708 0.6526 0.7452 0.8106 0.8324 0.8488 0.8433 0.8270 0.7888 0.7343 0.6826 0.5981 0.5300 0.4782 0.3910 0.3420 0.2847 0.2248 0.1621 0.0995 0.0668 0.0395 0.0232 0.0177 0.0204 0.0232 0.0259 0.0204 0.0232];

xE = [0.0267 0.0488 0.0856 0.1409 0.1759 0.2164 0.2514 0.3011 0.3269 0.3637 0.3969 0.4245 0.4503 0.4890 0.5313 0.5608 0.5939 0.6344 0.6694 0.6934 0.7192 0.7394 0.7523 0.7689 0.7891 0.8131 0.8481 0.8757 0.9070 0.9346 0.9604 0.9807 0.9936];
yE = [0.0232 0.0232 0.0232 0.0259 0.0259 0.0259 0.0313 0.0259 0.0259 0.0259 0.0368 0.0395 0.0477 0.0586 0.0777 0.0886 0.1213 0.1730 0.2466 0.2902 0.3638 0.5082 0.6499 0.7916 0.8924 0.9414 0.9550 0.9387 0.9060 0.8760 0.8542 0.8379 0.8188];

hFigure = figure('Position', [300 300 700 450], 'Color', 'w');
hAxes = xkcd_axes({'left', 'right'}, 'XTick', [0.45 0.60 0.7 0.8], ...
                  'XTickLabel', {'YARD', 'STEPS', 'DOOR', 'INSIDE'}, ...
                  'YTick', []);

hSpeed = xkcd_line(xS, yS, 'Parent', hAxes, 'Color', [0.5 0.5 0.5]);
hFear = xkcd_line(xF, yF, 'Parent', hAxes, 'Color', [0 0.5 1]);
hEmb = xkcd_line(xE, yE, 'Parent', hAxes, 'Color', 'r');

hText = xkcd_text(0.27, 0.9, ...
                  {'WALKING BACK TO MY'; 'FRONT DOOR AT NIGHT:'}, ...
                  'Parent', hAxes, 'EdgeColor', 'k', ...
                  'HorizontalAlignment', 'center');

hSpeedNote = xkcd_text(0.36, 0.35, {'FORWARD'; 'SPEED'}, ...
                       'Parent', hAxes, 'Color', 'k', ...
                       'HorizontalAlignment', 'center');
hSpeedLine = xkcd_line([0.4116 0.4282 0.4355 0.4411], ...
                       [0.3392 0.3256 0.3038 0.2820], ...
                       'Parent', hAxes, 'Color', 'k');
hFearNote = xkcd_text(0.15, 0.45, {'FEAR'; 'THAT THERE''S'; ...
                                   'SOMETHING'; 'BEIND ME'}, ...
                      'Parent', hAxes, 'Color', 'k', ...
                      'HorizontalAlignment', 'center');
hFearLine = xkcd_line([0.1906 0.1998 0.2127 0.2127 0.2201 0.2256], ...
                      [0.3501 0.3093 0.2629 0.2221 0.1975 0.1676], ...
                      'Parent', hAxes, 'Color', 'k');
hEmbNote = xkcd_text(0.88, 0.45, {'EMBARRASSMENT'}, ...
                     'Parent', hAxes, 'Color', 'k', ...
                     'HorizontalAlignment', 'center');
hEmbLine = xkcd_line([0.8168 0.8094 0.7983 0.7781 0.7578], ...
                     [0.4864 0.5436 0.5872 0.6063 0.6226], ...
                     'Parent', hAxes, 'Color', 'k');

И (трубы) вот и получился сюжет!

введите описание изображения здесь

gnovice
источник
2
Чудесно! Мой единственный комментарий заключается в том, что линии, которые указывают на текст, должны быть более тонкими и более изогнутыми (менее волнистыми).
бла
4
Это фантастика, хотя сюжет страдает от псевдонимов. Я написал краткий пост о том, как с этим бороться здесь: hugocarr.com/index/xkcd-style-graphs-in-matlab
Huguenot
28

Хорошо, вот моя менее грубая, но все еще не совсем там еще попытка:

%# init
%# ------------------------

noise = @(x,A) A*randn(size(x));
ns    = @(x,A) A*ones(size(x));


h = figure(2); clf, hold on
pos = get(h, 'position');
set(h, 'position', [pos(1:2) 800 450]);


blackline = {
    'k', ...
    'linewidth', 2};
axisline = {
    'k', ...
    'linewidth', 3};

textprops = {
    'fontName','Comic Sans MS',...
    'fontSize', 14,...
    'lineWidth',3};


%# Plot data
%# ------------------------
x  = 1:0.1:10;

y0 = sin(x).*exp(-x/30) + 3;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^6/.05) + 1;

y0 = y0 + noise(x, 0.01);
y1 = y1 + noise(x, 0.01);
y2 = y2 + noise(x, 0.01);

%# plot
plot(x,y0, 'color', [0.7 0.7 0.7], 'lineWidth',3);

plot(x,y1, 'w','lineWidth',7);
plot(x,y1, 'b','lineWidth',3);

plot(x,y2, 'w','lineWidth',7);
plot(x,y2, 'r','lineWidth',3);




%# text
%# ------------------------
ll(1) = text(1.3, 4.2,...
    {'Walking back to my'
    'front door at night:'});

ll(2) = text(5, 0.7, 'yard');
ll(3) = text(6.2, 0.7, 'steps');
ll(4) = text(7, 0.7, 'door');
ll(5) = text(8, 0.7, 'inside');

set(ll, textprops{:});


%# arrows & lines
%# ------------------------

%# box around "walking back..."
xx = 1.2:0.1:3.74;
yy = ns(xx, 4.6) + noise(xx, 0.007);
plot(xx, yy, blackline{:})

xx = 1.2:0.1:3.74;
yy = ns(xx, 3.8) + noise(xx, 0.007);
plot(xx, yy, blackline{:})

yy = 3.8:0.1:4.6;
xx = ns(yy, 1.2) + noise(yy, 0.007);
plot(xx, yy, blackline{:})

xx = ns(yy, 3.74) + noise(yy, 0.007);
plot(xx, yy, blackline{:})

%# left arrow
x_arr = 1.2:0.1:4.8;
y_arr = 0.65 * ones(size(x_arr)) + noise(x_arr, 0.005);
plot(x_arr, y_arr, blackline{:})
x_head = [1.1 1.6 1.62];
y_head = [0.65 0.72 0.57];
patch(x_head, y_head, 'k')

%# right arrow
x_arr = 8.7:0.1:9.8;
y_arr = 0.65 * ones(size(x_arr)) + noise(x_arr, 0.005);
plot(x_arr, y_arr, blackline{:})
x_head = [9.8 9.3 9.3];
y_head = [0.65 0.72 0.57];
patch(x_head, y_head, 'k')

%# left line on axis
y_line = 0.8:0.1:1.1;
x_line = ns(y_line, 6.5) + noise(y_line, 0.005);
plot(x_line, y_line, blackline{:})

%# right line on axis
y_line = 0.8:0.1:1.1;
x_line = ns(y_line, 7.2) + noise(y_line, 0.005);
plot(x_line, y_line, blackline{:})

%# axes
x_xax = x;
y_xax = 0.95 + noise(x_xax, 0.01);
y_yax = 0.95:0.1:5;
x_yax = x(1) + noise(y_yax, 0.01);
plot(x_xax, y_xax, axisline{:})
plot(x_yax, y_yax, axisline{:})


% finalize 
%# ------------------------

xlim([0.95 10])
ylim([0 5])
axis off

Результат:

Имитация XKCD в Matlab

Дела, которые необходимо сделать:

  1. Найдите лучшие функции (лучше определите их по частям)
  2. Добавьте «аннотации» и волнистые линии к кривым, которые они описывают
  3. Найдите лучший шрифт, чем Comic Sans!
  4. Обобщите все в функцию, plot2xkcdчтобы мы могли преобразовать любой сюжет / рисунок в стиль xkcd.
Роди Олденхуис
источник
1
Хорошая работа с цветами и топорами! Я чувствую, что они немного слишком нервные. +1 в любом случае.
Джонас
@HighPerormanceMark: Я все еще не думаю, что это все очень полезно, однако, это очень весело :)
Rody Oldenhuis
@RodyOldenhuis, почему не полезно? Я считаю, что стилизованные графики выглядят лучше, чем оригинальные. Добавление стиля, безусловно, является допустимой функцией.
Слейтон
2
@slayton: Давайте возьмем один очень продвинутый инструмент для вычисления чисел, который был разработан как очень эффективный, способный создавать красивые готовые к публикации сюжеты как можно точнее, и давайте использовать его для создания ... ** комиксов ** с ним , Извините, это просто глупо. Тем не менее, это очень весело , поэтому большинство людей проголосовало здесь, и вопрос был вновь открыт. Будет ли это полезным для будущих посетителей? Ну ... это действительно вдохновляет. Возможно, это пригласит некоторых людей изучать Matlab. Но для правильной работы в стиле xkcd потребуются хаки и методы, которые ... ну, по крайней мере, сомнительны :)
Rody Oldenhuis
6
@RodyOldenhuis: я буду использовать эти графики в своих презентациях. И обычно с помощью «хаков» вы действительно узнаете, как работает окружающая среда.
Джонас