xkcd-Stildiagramme in MATLAB

224

Grafik im xkcd-Stil

So haben talentierte Leute bereits herausgefunden, wie man in Mathematica , in LaTeX , in Python und in R Diagramme im xkcd- Stil erstellt .

Wie kann man mit MATLAB ein Diagramm erstellen, das wie oben aussieht?

Was ich versucht habe

Ich habe wackelige Linien erstellt, aber ich konnte keine wackeligen Äxte bekommen. Die einzige Lösung, an die ich dachte, war, sie mit wackeligen Linien zu überschreiben, aber ich möchte in der Lage sein, die tatsächlichen Achsen zu ändern. Ich konnte auch die Humor-Schriftart nicht zum Laufen bringen, das verwendete Codebit war:

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

Für die wackelige Linie experimentierte ich mit dem Hinzufügen eines kleinen zufälligen Rauschens und dem Glätten:

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

Aber ich konnte den weißen Hintergrund nicht so gestalten, dass er um sie herum erscheint, wenn sie sich schneiden ...

bla
quelle
9
Edit scheint zu befriedigen "hat zuerst einige Grundlagenforschung betrieben". Auch die Antworten hier sind nett. Wiedereröffnung.
Shog9

Antworten:

117

Ich sehe zwei Möglichkeiten, um dies zu lösen: Die erste Möglichkeit besteht darin, den x / y-Koordinaten der Plot-Features etwas Jitter hinzuzufügen. Dies hat den Vorteil, dass Sie ein Diagramm leicht ändern können, aber Sie müssen die Achsen selbst zeichnen, wenn Sie sie xkcdyfied haben möchten (siehe die Lösung von @Rody Oldenhuis ). Die zweite Möglichkeit besteht darin, ein nicht nervöses Diagramm zu erstellen und zu verwendenimtransform eine zufällige Verzerrung auf das Bild anzuwenden. Dies hat den Vorteil, dass Sie es mit jedem Plot verwenden können, aber Sie erhalten ein Bild, kein bearbeitbares Plot.

Ich werde zuerst # 2 und unten meinen Versuch auf # 1 zeigen (wenn Sie # 1 besser mögen, schauen Sie sich Rodys Lösung an !).

Geben Sie hier die Bildbeschreibung ein

Diese Lösung basiert auf zwei Schlüsselfunktionen: EXPORT_FIG aus dem Dateiaustausch, um einen Anti-Alias-Screenshot zu erhalten, und IMTRANSFORM , um eine Transformation zu erhalten.

%# 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)

Hier ist mein erster Versuch zu zittern

Geben Sie hier die Bildbeschreibung ein

%# 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
quelle
4
Genieße deine Zeit auf SO, solange du kannst! ;)
Gnovice
2
@gnovice: Es wird mein dritter sein. Ich hoffe, ich habe es inzwischen ziemlich gut herausgefunden :)
Jonas
@ Jonas gute Arbeit! Ich denke, Ihre Nummer 2 hat unter allen bisherigen Lösungen das richtige Gefühl für die Wackelbewegungen. Es fehlen jedoch immer noch die großen wackeligen Häkchen, ein Rahmen um den Text und handgezeichnete gekrümmte Linien, um vom Text auf eine Linie zu zeigen ...
bla
2
+1 für EXPORT_FIG. Dank Anti-Aliasing werden alle meine Grafiken ansprechender.
Yamaneko
1
@ JasonS: Entschuldigung, es war das nächste, das ich zu diesem Zeitpunkt zur Verfügung hatte.
Jonas
92

Anstatt alle verschiedenen Plotfunktionen erneut zu implementieren, wollte ich ein generisches Tool erstellen, mit dem jedes vorhandene Plot in ein xkcd-Plot konvertiert werden kann.

Dieser Ansatz bedeutet, dass Sie Diagramme erstellen und mit den Standardfunktionen von MATLAB formatieren können. Wenn Sie fertig sind, können Sie das Diagramm in einem xkcd-Stil neu rendern und dabei den Gesamtstil des Diagramms beibehalten.

Beispiele

Handlung Geben Sie hier die Bildbeschreibung ein

Bar & Grundstück

Geben Sie hier die Bildbeschreibung ein

Box-Plot Geben Sie hier die Bildbeschreibung ein

Wie es funktioniert

Die Funktion iteriert über die untergeordneten Elemente einer Achse. Wenn die Kinder vom Typ sind lineoder patches sie leicht verzerrt. Wenn das Kind vom Typ ist hggroup, iteriert es auf den Unterkindern des hggroup. Ich habe Pläne, andere Plottypen zu unterstützen, z. B. image, aber es ist nicht klar, wie das Bild am besten verzerrt werden kann, um einen xkcd-Stil zu erhalten.

Um sicherzustellen, dass die Verzerrungen gleichmäßig aussehen (dh kurze Linien werden nicht mehr als lange Linien verzerrt), messe ich die Linienlänge in Pixel und setze dann das Sample proportional zu seiner Länge auf. Ich füge dann jedem N-ten Sample Rauschen hinzu, das Linien erzeugt, die mehr oder weniger die gleiche Verzerrung aufweisen.

Der Code

Anstatt mehrere hundert Codezeilen einzufügen, verweise ich einfach auf einen Kern der Quelle . Zusätzlich sind der Quellcode und der Code zum Generieren der obigen Beispiele frei verfügbarer GitHub .

Wie Sie den Beispielen entnehmen können, werden die Achsen selbst noch nicht verzerrt, obwohl ich beabsichtige, sie zu implementieren, sobald ich herausgefunden habe, wie dies am besten funktioniert.

Slayton
quelle
4
Nett! Ich habe einen ähnlichen Code export_figbearbeitet, der die Route implementiert , dh zuerst den Plot xkcd-ähnlich formatiert und dann das Bild verzerrt.
Jonas
4
Vielen Dank. Ich bin sehr stolz auf die Boxplots. Ich war überrascht über das Ausmaß an Hacking, das erforderlich ist, damit diese Pläne auftauchen.
Slayton
Ich werde es verwenden, um meine gesamte Präsentation in einen XKCD-Stil umzuwandeln.
Yamaneko
Hallo Slayton, die sind fantastisch! Ich habe nur eine Frage: Gibt es eine Möglichkeit, die Achsen auch cartoony / xkcd-ish zu machen? Das würde es für mich tun und ich könnte es benutzen! :-) Vielen Dank ...
Spacey
@Learnaholic AFAIK Matlab bietet keine APIs (dokumentiert oder undokumentiert), um die Art und Weise zu ändern, wie Achsen gerendert werden
Slayton
63

Der erste Schritt ... finden Sie eine Systemschriftart, die Ihnen gefällt (verwenden Sie die Funktion, um listfontszu sehen, was verfügbar ist) oder installieren Sie eine, die dem Handschriftstil von xkcd entspricht . Ich habe eine TrueType-Schriftart "Humor Sans" von Benutzer ch00f gefunden, die in diesem Blog-Beitrag erwähnt wurde , und werde sie für meine nachfolgenden Beispiele verwenden.

Aus meiner Sicht benötigen Sie im Allgemeinen drei verschiedene modifizierte Grafikobjekte, um diese Art von Diagrammen zu erstellen: ein Achsenobjekt , ein Linienobjekt und ein Textobjekt . Vielleicht möchten Sie auch ein Anmerkungsobjekt , um die Dinge einfacher zu machen, aber ich habe darauf verzichtet, da es schwieriger zu implementieren sein könnte als die oben genannten drei Objekte.

Ich habe Wrapper-Funktionen erstellt, mit denen die drei Objekte erstellt wurden, wobei bestimmte Eigenschafteneinstellungen überschrieben wurden, um sie xkcd-ähnlicher zu machen. Eine Einschränkung besteht darin, dass die neuen Grafiken, die sie erstellen, in bestimmten Fällen nicht aktualisiert werden (z. B. Begrenzungsrahmen für Textobjekte beim Ändern der Achsengröße). Dies könnte jedoch durch eine vollständigere objektorientierte Implementierung berücksichtigt werden, bei der vom Handle geerbt wird Klasse , Verwenden von Ereignissen und Listenern usw. Im Moment sind hier meine einfacheren Implementierungen:

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

Und hier ist ein Beispielskript, das diese verwendet, um den obigen Comic neu zu erstellen. Ich habe die Linien neu erstellt, indem ich ginputPunkte im Plot mit der Maus markiert, sie erfasst und dann so gezeichnet habe, wie ich es wollte:

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');

Und (Trompeten) hier ist die resultierende Handlung!:

Geben Sie hier die Bildbeschreibung ein

gnovice
quelle
2
Wunderbar! Mein einziger Kommentar ist, dass die Linien, die vom Text zeigen, dünner und gebogener sein sollten (weniger wackelig).
Bla
4
Das ist fantastisch, obwohl die Handlung unter Aliasing leidet. Ich schrieb hier einen kurzen Beitrag darüber, wie man damit umgeht
Huguenot
28

OK, hier ist mein weniger roher, aber immer noch nicht ganz vorhandener Versuch:

%# 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

Ergebnis:

XKCD-Nachahmung in Matlab

Dinge die zu tun sind:

  1. Finden Sie bessere Funktionen (definieren Sie sie stückweise besser)
  2. Fügen Sie den beschriebenen Kurven "Anmerkungen" und Wellenlinien hinzu
  3. Finden Sie eine bessere Schriftart als Comic Sans!
  4. Verallgemeinern Sie alles in eine Funktion, plot2xkcddamit wir jede Handlung / Figur in den xkcd-Stil konvertieren können .
Rody Oldenhuis
quelle
1
Gute Arbeit mit Farben und Äxten! Ich finde sie allerdings etwas zu nervös. +1 sowieso.
Jonas
@ HighPerormanceMark: Ich denke immer noch nicht, dass dies alles sehr nützlich ist, aber es macht großen Spaß :)
Rody Oldenhuis
@RodyOldenhuis warum nicht nützlich? Ich finde die gestalteten Handlungen besser als die ursprünglichen Handlungen. Das Hinzufügen von Stil ist sicherlich eine gültige Funktion.
Slayton
2
@slayton: Nehmen wir ein sehr fortschrittliches Tool zum Knacken von Zahlen, das so konzipiert wurde, dass es sehr effizient ist und in der Lage ist, schöne, publikationsbereite Handlungen so genau wie möglich zu erstellen, und verwenden Sie es, um ... ** Comics ** damit zu erstellen . Entschuldigung, das ist nur albern. Es macht jedoch großen Spaß , weshalb die meisten Leute hier gestimmt haben und was die Frage wieder geöffnet hat. Wird dies für zukünftige Besucher von Nutzen sein? Nun ... es ist zu inspirieren. Vielleicht lädt es einige Leute ein, Matlab zu lernen. Aber damit xkcd-
artig
6
@RodyOldenhuis: Ich werde diese Grafiken in meinen Präsentationen verwenden. Und normalerweise lernen Sie mit den "Hacks" wirklich, wie die Umgebung funktioniert.
Jonas