Graphes de style xkcd dans MATLAB

225

graphique de style xkcd

Donc , les gens talentueux ont compris comment faire xkcd graphiques de style dans Mathematica , en LATEX , en Python et en R déjà.

Comment peut-on utiliser MATLAB pour produire un tracé qui ressemble à celui ci-dessus?

Ce que j'ai essayé

J'ai créé des lignes ondulées, mais je n'ai pas pu obtenir d'axes ondulés. La seule solution à laquelle j'ai pensé était de les écraser avec des lignes ondulées, mais je veux pouvoir changer les axes réels. Je ne pouvais pas non plus faire fonctionner la police Humor, le bit de code utilisé était:

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

Pour la ligne ondulée, j'ai expérimenté l'ajout d'un petit bruit aléatoire et le lissage:

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

Mais je n'ai pas pu faire apparaître le fond blanc autour d'eux lorsqu'ils se croisent ...

bla
la source
9
Edit semble satisfaire "a fait quelques recherches de base en premier". De plus, les réponses ici sont agréables. Réouverture.
Shog9

Réponses:

118

Je vois deux façons de résoudre ce problème: La première consiste à ajouter un peu de gigue aux coordonnées x / y des caractéristiques du tracé. Cela a l'avantage que vous pouvez facilement modifier un tracé, mais vous devez dessiner les axes vous-même si vous souhaitez les avoir xkcdyfied (voir la solution de @Rody Oldenhuis ). La deuxième façon consiste à créer un tracé non instable et à utiliser imtransformpour appliquer une distorsion aléatoire à l'image. Cela a l'avantage que vous pouvez l'utiliser avec n'importe quel tracé, mais vous vous retrouverez avec une image, pas un tracé modifiable.

Je montrerai le # 2 en premier, et ma tentative de # 1 ci-dessous (si vous préférez le # 1, regardez la solution de Rody !).

entrez la description de l'image ici

Cette solution repose sur deux fonctions clés: EXPORT_FIG à partir de l'échange de fichiers pour obtenir une capture d'écran anticrénelée et IMTRANSFORM pour obtenir une transformation.

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

Voici ma première tentative de trembler

entrez la description de l'image ici

%# 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
la source
4
Profitez de votre temps sur SO pendant que vous le pouvez! ;)
gnovice
2
@gnovice: Ce sera ma troisième. J'espère que je l'ai à peu près compris maintenant :)
Jonas
@Jonas bon travail! Je pense que votre n ° 2 a eu la bonne idée des mouvements, parmi toutes les solutions jusqu'à présent. Cependant, il manque toujours les grandes tiques ondulées, un cadre autour du texte et des lignes courbes dessinées à la main pour pointer du texte vers une ligne ...
bla
2
+1 pour EXPORT_FIG. Rendre tous mes graphiques plus agréables grâce à l'anti-aliasing.
Yamaneko
1
@JasonS: désolé, c'était le plus proche dont je disposais à l'époque.
Jonas
92

Plutôt que de réimplémenter toutes les différentes fonctions de traçage, j'ai voulu créer un outil générique qui pourrait convertir n'importe quel tracé existant en un tracé de style xkcd.

Cette approche signifie que vous pouvez créer des tracés et les styliser à l'aide des fonctions MATLAB standard , puis lorsque vous avez terminé, vous pouvez ensuite restituer le tracé dans un style xkcd tout en préservant le style général du tracé.

Exemples

Terrain Entrez la description de l'image ici

Bar & Terrain

Entrez la description de l'image ici

Box & Plot Entrez la description de l'image ici

Comment ça fonctionne

La fonction fonctionne en itérant sur les enfants d'un axe. Si les enfants sont de type lineou patchça les déforme légèrement. Si l'enfant est de type, hggroupil répète les sous-enfants du hggroup. J'ai l'intention de prendre en charge d'autres types de tracés, tels que image, mais il n'est pas clair quel est le meilleur moyen de déformer l'image pour avoir un style xkcd.

Enfin, pour m'assurer que les distorsions semblent uniformes (c'est-à-dire que les lignes courtes ne sont pas distordues plus que les lignes longues), je mesure la longueur de la ligne en pixels, puis jusqu'à l'échantillon proportionnel à sa longueur. J'ajoute ensuite du bruit à chaque Nième échantillon qui produit des lignes qui ont plus ou moins la même distorsion.

Le code

Plutôt que de coller plusieurs centaines de lignes de code, je vais simplement créer un lien vers un résumé de la source . De plus, le code source et le code pour générer les exemples ci-dessus sont disponibles gratuitement GitHub .

Comme vous pouvez le voir dans les exemples, cela ne déforme pas encore les axes eux-mêmes, même si je prévois de les mettre en œuvre dès que je trouverai la meilleure façon de le faire.

slayton
la source
4
Agréable! J'ai travaillé un morceau de code similaire qui implémente l' export_figitinéraire, c'est-à-dire qu'il formate d'abord l'intrigue comme xkcd, puis déforme l'image.
Jonas
4
Merci. Je suis vraiment fier des boîtes à moustaches. J'ai été surpris du niveau de piratage requis pour que ces parcelles apparaissent.
slayton
Je vais l'utiliser pour convertir toute ma présentation dans un style XKCD.
Yamaneko
Salut Slayton, ce sont fantastiques! J'ai juste une question, est-il possible de faire également les axes cartoony / xkcd-ish? Cela le ferait pour moi et je pourrais l'utiliser! :-) Merci beaucoup ...
Spacey
@Learnaholic AFAIK matlab ne fournit aucune API (documentée ou non) pour changer la façon dont les axes sont rendus
slayton
63

La première étape ... trouvez une police système que vous aimez (utilisez la fonction listfontspour voir ce qui est disponible) ou installez-en une qui correspond au style d'écriture manuscrite de xkcd . J'ai trouvé une police TrueType "Humour Sans" de l'utilisateur ch00f mentionné dans cet article de blog , et je l'utiliserai pour mes exemples suivants.

Selon moi, vous aurez généralement besoin de trois objets graphiques modifiés différents pour créer ces sortes de graphiques: un objet axes , un objet ligne et un objet texte . Vous pouvez également souhaiter un objet d'annotation pour faciliter les choses, mais je l'ai prévenu pour l'instant car il pourrait être plus difficile à implémenter que les trois objets ci-dessus.

J'ai créé des fonctions d'encapsuleur qui ont créé les trois objets, en remplaçant certains paramètres de propriété pour les rendre plus similaires à xkcd. Une limitation est que les nouveaux graphiques qu'ils produisent ne seront pas mis à jour dans certains cas (comme les cadres de délimitation sur les objets texte lors du redimensionnement des axes), mais cela pourrait être pris en compte avec une implémentation orientée objet plus complète qui implique l'héritage de la poignée classe , en utilisant des événements et des écouteurs , etc. Pour l'instant, voici mes implémentations plus simples:

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

Et voici un exemple de script qui les utilise pour recréer la bande dessinée ci-dessus. J'ai recréé les lignes en utilisant ginputpour marquer des points dans l'intrigue avec la souris, en les capturant, puis en les traçant comme je le voulais:

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

Et (trompettes) voici l'intrigue qui en résulte!:

entrez la description de l'image ici

gnovice
la source
2
Merveilleux! mon seul commentaire est que les lignes qui pointent du texte devraient être plus fines et plus courbes (moins ondulées).
bla
4
C'est fantastique, bien que l'intrigue souffre d'alias. J'ai écrit un bref article sur la façon de traiter cela ici: hugocarr.com/index/xkcd-style-graphs-in-matlab
Huguenot
28

OK alors, voici ma tentative moins brute mais pas encore tout à fait là-bas:

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

Résultat:

Imitation XKCD dans Matlab

Choses à faire:

  1. Trouver de meilleures fonctions (mieux les définir par morceaux)
  2. Ajoutez des "annotations" et des lignes ondulées aux courbes qu'elles décrivent
  3. Trouvez une meilleure police que Comic Sans!
  4. Généralisez tout en une fonction plot2xkcdafin que nous puissions convertir n'importe quel tracé / figure au style xkcd.
Rody Oldenhuis
la source
1
Beau travail avec des couleurs et des haches! Je pense cependant qu'ils sont un peu trop nerveux. +1 de toute façon.
Jonas
@HighPerormanceMark: Je ne pense toujours pas que tout cela soit très utile, cependant, c'est très amusant :)
Rody Oldenhuis
@RodyOldenhuis pourquoi pas utile? Je trouve les parcelles stylisées plus belles que les parcelles originales. Ajouter du style est certainement une fonction valable.
slayton
2
@slayton: Prenons un outil de calcul de nombres très avancé qui a été conçu pour être super efficace, capable de créer de superbes graphiques prêts à publier aussi précisément que possible, et utilisons-le pour créer ... ** des bandes dessinées ** avec . Désolé, c'est juste idiot. C'est très amusant cependant, c'est pourquoi la plupart des gens ici ont voté et ce qui a rouvert la question. Est-ce que cela sera utile aux futurs visiteurs? Eh bien ... il n'inspire. Peut-être que cela invitera certaines personnes à apprendre Matlab. Mais faire fonctionner le style xkcd correctement nécessitera des hacks et des techniques qui sont uhm ... discutables à tout le moins :)
Rody Oldenhuis
6
@RodyOldenhuis: Pour ma part, j'utiliserai ces graphiques dans mes présentations. Et c'est généralement avec les "hacks" que l'on apprend vraiment comment fonctionne l'environnement.
Jonas