Wykresy w stylu xkcd w MATLAB

224

Wykres w stylu xkcd

Tak utalentowani ludzie zorientowali się, jak sprawić, by xkcd wykresy styl w Mathematica , w lateks , w Pythonie oraz w badania już.

Jak wykorzystać MATLAB do stworzenia fabuły, która wygląda jak powyższa?

Co próbowałem

Tworzyłem kręte linie, ale nie mogłem uzyskać krętych osi. Jedynym rozwiązaniem, o którym myślałem, było zastąpienie ich krętymi liniami, ale chcę móc zmieniać rzeczywiste osie. Nie mogłem również uruchomić czcionki Humor, użyty bit kodu to:

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

W przypadku krętej linii eksperymentowałem z dodaniem małego przypadkowego hałasu i wygładzeniem:

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

Ale nie mogłem sprawić, by białe tło pojawiło się wokół nich, kiedy się przecinają ...

bla
źródło
9
Wydaje się, że edycja spełnia oczekiwania „najpierw wykonał kilka podstawowych badań”. Także odpowiedzi tutaj są miłe. Ponowne otwarcie.
Shog9

Odpowiedzi:

117

Widzę dwa sposoby rozwiązania tego problemu: Pierwszy sposób polega na dodaniu drgań do współrzędnych x / y elementów wykresu. Ma to tę zaletę, że możesz łatwo modyfikować wykres, ale musisz sam narysować osie, jeśli chcesz je xkcdyfied (patrz rozwiązanie @Rody Oldenhuis ). Drugi sposób polega na utworzeniu fabuły pozbawionej wstrząsów i zastosowaniu imtransformdo losowego zniekształcenia obrazu. Ma to tę zaletę, że można go używać z dowolną fabułą, ale skończy się to obrazem, a nie edytowalną fabułą.

Najpierw pokażę # 2, a moja próba # 1 poniżej (jeśli bardziej ci się podoba # 1, spójrz na rozwiązanie Rody !).

wprowadź opis zdjęcia tutaj

To rozwiązanie opiera się na dwóch kluczowych funkcjach: EXPORT_FIG z wymiany plików, aby uzyskać zrzut ekranu z aliasingiem , oraz IMTRANSFORM, aby uzyskać transformację.

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

Oto moja pierwsza próba drżenia

wprowadź opis zdjęcia tutaj

%# 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
źródło
4
Ciesz się czasem na SO, póki możesz! ;)
gnovice
2
@gnovice: To będzie mój trzeci. Mam nadzieję, że udało mi się już to rozgryźć :)
Jonas,
@Jonas dobra robota! Myślę, że Twoje # 2 ma właściwe wyczucie peruk, spośród wszystkich dotychczasowych rozwiązań. Nadal jednak brakuje mu dużych, kręcących się tyknięć, ramki wokół tekstu i ręcznie narysowanych zakrzywionych linii, które wskazują punkt od tekstu do linii ...
bla
2
+1 dla EXPORT_FIG. Sprawiając, że wszystkie moje wykresy są przyjemniejsze dzięki wygładzaniu krawędzi.
Yamaneko
1
@JasonS: przepraszam, to było najbliższe, jakie miałem w tym czasie dostępne.
Jonas
92

Zamiast ponownie wdrożyć wszystkie różne funkcje drukowania, chciałem stworzyć ogólne narzędzie, które może przekonwertować dowolny istniejący wykres na wykres w stylu xkcd.

Podejście to oznacza, że ​​możesz tworzyć wykresy i nadawać im styl za pomocą standardowych funkcji MATLAB, a po zakończeniu możesz ponownie renderować wykres w stylu xkcd, zachowując ogólny styl wykresu.

Przykłady

Wątek Wpisz opis zdjęcia tutaj

Bar & Plot

Wpisz opis zdjęcia tutaj

Pudełko i fabuła Wpisz opis zdjęcia tutaj

Jak to działa

Ta funkcja działa poprzez iterację nad dziećmi osi. Jeśli dzieci są tego typu linelub patchlekko je zniekształca. Jeśli dziecko jest typu hggroup, iteruje się w podrzędnych hggroup. Mam plany obsługi innych typów wykresów, takich jak image, ale nie jest jasne, jaki jest najlepszy sposób na zniekształcenie obrazu w stylu xkcd.

Wreszcie, aby upewnić się, że zniekształcenia wyglądają jednolicie (tzn. Krótkie linie nie są zniekształcone bardziej niż długie linie), mierzę długość linii w pikselach, a następnie próbkę proporcjonalnie do jej długości. Następnie dodaję szum do każdej N-tej próbki, która wytwarza linie, które mają mniej więcej tyle samo zniekształceń.

Kod

Zamiast wklejać kilkaset wierszy kodu, po prostu odsyłam do istoty źródła . Dodatkowo kod źródłowy i kod do wygenerowania powyższych przykładów są swobodnie dostępne GitHub .

Jak widać z przykładów, nie zniekształca to jeszcze samych osi, chociaż planuję wdrożyć, jak tylko wymyślę najlepszy sposób, aby to zrobić.

slayton
źródło
4
Miły! Pracowałem nad podobnym fragmentem kodu, który implementuje export_figtrasę, tzn. Najpierw formatuje wykres podobny do xkcd, a następnie zniekształca obraz.
Jonas
4
Dzięki. Jestem naprawdę dumny z fabuł. Byłem zaskoczony poziomem hakowania wymaganym do pokazania się tych fabuł.
slayton
Wykorzystam go do przekonwertowania całej prezentacji na styl XKCD.
Yamaneko
Cześć Slayton, są fantastyczne! Mam tylko jedno pytanie, czy istnieje sposób, aby osi cartoony / xkcd-ish? To by mi wystarczyło i byłbym w stanie z niego skorzystać! :-) Wielkie dzięki ...
Spacey
@Learnaholic AFAIK matlab nie udostępnia żadnych interfejsów API (udokumentowanych lub nieudokumentowanych), które
mogłyby
63

Pierwszy krok ... znajdź czcionkę systemową, którą lubisz (użyj tej funkcji, listfontsaby zobaczyć, co jest dostępna) lub zainstaluj taką, która pasuje do stylu pisma od xkcd . Znalazłem czcionkę TrueType „Humor Sans” od użytkownika ch00f wspomnianą w tym poście na blogu i wykorzystam ją do moich kolejnych przykładów.

Jak ja to widzę, to trzeba zazwyczaj trzy różne zmodyfikowane grafiki obiektów, aby uczynić te rodzaje wykresów: AN osie sprzeciwić , a obiekt liniowy , a obiekt tekstowy . Możesz także chcieć, aby obiekt adnotacji uprościł sprawę, ale zignorowałem to na razie, ponieważ może być trudniej zaimplementować niż powyższe trzy obiekty.

Utworzyłem funkcje opakowania, które utworzyły trzy obiekty, przesłaniając niektóre ustawienia właściwości, aby były bardziej podobne do xkcd. Jednym ograniczeniem jest to, że nowa grafika, którą tworzą, nie będzie aktualizowana w niektórych przypadkach (takich jak obwiednia na obiektach tekstowych podczas zmiany rozmiaru osi), ale można to wyjaśnić za pomocą pełniejszej implementacji obiektowej, która obejmuje dziedziczenie z uchwytu klasa , używanie zdarzeń i detektorów itp. Na razie oto moje prostsze implementacje:

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

A oto przykładowy skrypt, który wykorzystuje je do odtworzenia powyższego komiksu. Odtworzyłem linie za pomocą ginputmyszy, zaznaczając punkty na wykresie, przechwytując je, a następnie wykreślając je tak, jak chciałem:

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

A (trąbki) oto wynikowy spisek !:

wprowadź opis zdjęcia tutaj

gnovice
źródło
2
Wspaniale! moim jedynym komentarzem jest to, że linie wskazujące na tekst powinny być cieńsze i bardziej zakrzywione (mniej peruwiańskie).
bla
4
To fantastyczne, choć fabuła cierpi na aliasing. Napisałem krótki post o tym, jak sobie z tym poradzić tutaj: hugocarr.com/index/xkcd-style-graphs-in-matlab
Huguenot
28

OK, oto moja mniej prymitywna-ale-wciąż-nie-całkiem-jeszcze-próba:

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

Wynik:

Imitacja XKCD w Matlabie

Rzeczy do zrobienia:

  1. Znajdź lepsze funkcje (lepiej zdefiniuj je fragmentarycznie)
  2. Dodaj „adnotacje” i faliste linie do opisywanych krzywych
  3. Znajdź lepszą czcionkę niż Comic Sans!
  4. Uogólnij wszystko na funkcję plot2xkcd, abyśmy mogli przekonwertować dowolny wykres / rysunek na styl xkcd.
Rody Oldenhuis
źródło
1
Dobra robota z kolorami i toporami! Jednak wydaje mi się, że są trochę zbyt roztrzęsieni. W każdym razie +1.
Jonas
@HighPerormanceMark: Nadal nie sądzę, że to wszystko jest bardzo przydatne, ale świetna zabawa :)
Rody Oldenhuis
@RodyOldenhuis dlaczego nie jest użyteczny? Uważam, że stylizowane działki wyglądają lepiej niż oryginalne. Dodanie stylu jest z pewnością prawidłową funkcją.
slayton
2
@slayton: Weźmy jedno bardzo zaawansowane narzędzie do łamania liczb, które zostało zaprojektowane tak, aby było super wydajne, zdolne do tworzenia pięknych, gotowych do publikacji fabuł tak precyzyjnie, jak to możliwe, i użyjmy go, aby ... ** komiks ** z nim . Przepraszam, to po prostu głupie. To jednak świetna zabawa , dlatego większość ludzi tutaj głosowała i to, co sprawiło, że pytanie zostało ponownie otwarte. Czy przyda się to przyszłym użytkownikom? Cóż ... to ma inspirować. Być może zachęci to niektórych ludzi do nauki Matlaba. Ale poprawne działanie stylu xkcd będzie wymagać hacków i technik, które są co najmniej ... wątpliwe :)
Rody Oldenhuis
6
@RodyOldenhuis: Ja, na przykład, wykorzystam te wykresy w moich prezentacjach. I zwykle dzięki „hackom” naprawdę uczysz się, jak działa środowisko.
Jonas,