กราฟสไตล์ xkcd ใน MATLAB


224

กราฟสไตล์ xkcd

ดังนั้นคนที่มีความสามารถได้คิดวิธีการที่จะทำให้xkcdกราฟสไตล์ใน Mathematica , ในน้ำยาง , ในหลามและใน Rแล้ว

เราจะใช้ MATLAB ในการสร้างพล็อตที่ดูเหมือนกับข้างบนได้อย่างไร?

สิ่งที่ฉันได้ลอง

ฉันสร้างเส้นที่สั่นคลอน แต่ฉันไม่สามารถรับแกนที่บิดเบี้ยวได้ ทางออกเดียวที่ฉันคิดว่าจะเขียนทับพวกเขาด้วยเส้น wiggly แต่ฉันต้องการที่จะสามารถเปลี่ยนแกนจริง ฉันยังไม่สามารถใช้ฟอนต์ Humor เพื่อทำงานรหัสบิตที่ใช้คือ:

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

สำหรับบรรทัด wiggly ฉันได้ทดลองเพิ่มเสียงแบบสุ่มและการทำให้เรียบ:

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

แต่ฉันไม่สามารถทำให้พื้นหลังสีขาวปรากฏขึ้นรอบ ๆ พวกเขาเมื่อพวกเขาตัดกัน ...


9
การแก้ไขดูเหมือนว่าจะทำให้พอใจ "ได้ทำการวิจัยขั้นพื้นฐานก่อน" นอกจากนี้คำตอบที่นี่ก็ดี เปิดใหม่
Shog9

คำตอบ:


117

ฉันเห็นสองวิธีในการแก้ปัญหานี้: วิธีแรกคือการเพิ่ม jitter ลงในพิกัด x / y ของคุณสมบัติการลงจุด นี่เป็นข้อดีที่คุณสามารถปรับเปลี่ยนพล็อตได้อย่างง่ายดาย แต่คุณต้องวาดแกนเองถ้าคุณต้องการให้ xkcdyfied (ดูที่@Rody Oldenhuis 'solution ) วิธีที่สองคือการสร้างพล็อตที่ไม่กระวนกระวายใจและใช้imtransformในการใช้การบิดเบือนแบบสุ่มกับภาพ นี่คือข้อดีที่คุณสามารถใช้กับพล็อตใด ๆ แต่คุณจะจบลงด้วยภาพไม่ใช่พล็อตที่แก้ไขได้

ฉันจะแสดง # 2 ก่อนและความพยายามของฉันที่ # 1 ด้านล่าง (ถ้าคุณชอบ # 1 ดีกว่าดูวิธีแก้ปัญหาของ Rody !)

ป้อนคำอธิบายรูปภาพที่นี่

โซลูชันนี้ใช้สองฟังก์ชั่นหลัก: 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')

4
สนุกกับเวลาของคุณในขณะที่คุณสามารถ! ;)
gnovice

2
@gnovice: มันจะเป็นหนึ่งในสามของฉัน ฉันหวังว่าฉันจะคิดออกมาได้แล้วตอนนี้ :)
Jonas

@ Jonas เป็นงานที่ดี! ฉันคิดว่า # 2 ของคุณมีความรู้สึกที่ถูกต้องสำหรับ wiggles ในบรรดาวิธีแก้ไขทั้งหมด อย่างไรก็ตามมันยังคงพลาดติ๊กใหญ่โตกรอบรอบข้อความและวาดเส้นโค้งให้ชี้จากข้อความหนึ่งไปยังอีกบรรทัดหนึ่ง ...
bla

2
+1 สำหรับ EXPORT_FIG ทำให้กราฟทั้งหมดของฉันน่าพึงพอใจยิ่งขึ้นด้วยการลดรอยหยัก
Yamaneko

1
@ JasonS: ขออภัยมันใกล้เคียงที่สุดที่ฉันมีให้ในเวลา
Jonas

92

แทนที่จะใช้ฟังก์ชั่นการพล็อตต่าง ๆ ทั้งหมดอีกครั้งฉันต้องการสร้างเครื่องมือทั่วไปที่สามารถแปลงพล็อตที่มีอยู่ให้เป็นพล็อตสไตล์ xkcd

วิธีการนี้หมายความว่าคุณสามารถสร้างแปลงและจัดรูปแบบโดยใช้ฟังก์ชันMATLABมาตรฐานและเมื่อเสร็จแล้วคุณสามารถแสดงผลพล็อตในรูปแบบ xkcd อีกครั้งในขณะที่รักษารูปแบบโดยรวมของพล็อต

ตัวอย่าง

พล็อต ป้อนคำอธิบายภาพที่นี่

บาร์ & แปลง

ป้อนคำอธิบายภาพที่นี่

กล่อง & แปลง ป้อนคำอธิบายภาพที่นี่

มันทำงานอย่างไร

ฟังก์ชั่นนี้ทำงานได้โดยการทำซ้ำ ๆ กับแกนของเด็ก หากเด็กเป็นประเภทlineหรือpatchมันผิดเพี้ยนไปเล็กน้อย ถ้าหากเด็กเป็นประเภทhggroupแล้ว iterates hggroupบนย่อยของเด็ก ฉันมีแผนที่จะสนับสนุนพล็อตประเภทอื่น ๆ เช่นimageแต่ไม่ชัดเจนว่าวิธีใดที่ดีที่สุดในการบิดเบือนภาพเพื่อให้มีรูปแบบ xkcd

ในที่สุดเพื่อให้แน่ใจว่าการบิดเบี้ยวดูสม่ำเสมอ (นั่นคือเส้นสั้นไม่ได้ถูกบิดเบือนเกินเส้นยาว) ฉันวัดความยาวบรรทัดเป็นพิกเซลแล้วจึงเพิ่มสัดส่วนตัวอย่างตามความยาว จากนั้นฉันจะเพิ่มสัญญาณรบกวนให้กับทุกตัวอย่างของ Nth ที่สร้างเส้นที่มีจำนวนความผิดเพี้ยนมากขึ้นหรือน้อยลง

รหัส

แทนที่จะวางหลายร้อยสายรหัสฉันเพิ่งจะเชื่อมโยงไปยังส่วนสำคัญของแหล่งที่มา นอกจากนี้รหัสแหล่งที่มาและรหัสเพื่อสร้างตัวอย่างข้างต้นที่มีอยู่ได้อย่างอิสระGitHub

อย่างที่คุณเห็นจากตัวอย่างมันยังไม่บิดเบือนแกนตัวเองแม้ว่าฉันวางแผนที่จะใช้งานได้ทันทีที่ฉันหาวิธีที่ดีที่สุดในการทำเช่นนั้น


4
ดี! ฉันใช้งานโค้ดที่คล้ายกันซึ่งใช้export_figเส้นทางนั่นคือการจัดรูปแบบพล็อต xkcd แบบแรกแล้วบิดเบือนภาพ
Jonas

4
ขอบคุณ ฉันภูมิใจในแผนการแปลงมาก ฉันรู้สึกประหลาดใจที่ระดับการแฮ็คต้องได้รับแผนการเหล่านั้นเพื่อแสดง
slayton

ฉันจะใช้มันเพื่อแปลงงานนำเสนอทั้งหมดของฉันให้เป็นสไตล์ XKCD
Yamaneko

สวัสดี Slayton มันยอดเยี่ยมมาก! ฉันมีคำถามเดียวมีวิธีที่จะทำให้แกน cartoony / xkcd-ish? นั่นจะทำเพื่อฉันและฉันจะสามารถใช้มันได้! :-) ขอบคุณมาก ...
Spacey

MATLAB @Learnaholic AFAIK ไม่ได้ให้ API ใด ๆ (เอกสารหรือไม่มีเอกสาร) เพื่อเปลี่ยนวิธีการที่จะกลายเป็นแกน
Slayton

63

ขั้นตอนแรก ... หาระบบตัวอักษรที่คุณชอบ (ใช้ฟังก์ชั่นlistfontsที่จะเห็นสิ่งที่มีอยู่) หรือติดตั้งอย่างใดอย่างหนึ่งที่ตรงกับสไตล์การเขียนด้วยลายมือจากxkcd ฉันพบตัวอักษร TrueType "Humor Sans"จากผู้ใช้ ch00f ที่กล่าวถึงในโพสต์บล็อกนี้และจะใช้สำหรับตัวอย่างที่ตามมาของฉัน

ที่ผมเห็นมันคุณจะต้องทั่วไปสามกราฟิกการแก้ไขที่แตกต่างกันเพื่อให้วัตถุแปลก ๆ เหล่านี้กราฟ: ทางแกนวัตถุเป็นวัตถุเส้นและวัตถุข้อความ คุณอาจต้องการให้วัตถุคำอธิบายประกอบทำสิ่งต่าง ๆ ได้ง่ายขึ้น แต่ฉันก็บอกล่วงหน้าว่าในขณะนี้เพราะอาจนำไปใช้งานได้ยากกว่าวัตถุสามชิ้นด้านบน

ฉันสร้างฟังก์ชั่น wrapper ที่สร้างวัตถุสามชิ้นแทนที่การตั้งค่าคุณสมบัติบางอย่างเพื่อให้เหมือน 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');

และ(แตร)นี่คือพล็อตที่เกิดขึ้น!:

ป้อนคำอธิบายรูปภาพที่นี่


2
ยอดเยี่ยม! ความคิดเห็นเดียวของฉันคือเส้นที่ชี้จากข้อความควรเป็นทินเนอร์และโค้งมากขึ้น (ลดลงเล็กน้อย)
bla

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 อยู่ดี
Jonas

@HighPerormanceMark: ผมยังไม่คิดว่านี่เป็นสิ่งที่มีประโยชน์มาก แต่ก็สนุกดี :)
rody Oldenhuis

@RodyOldenhuis ทำไมไม่มีประโยชน์ ฉันพบว่าแปลงที่มีสไตล์ดูดีกว่าแปลงดั้งเดิม การเพิ่มสไตล์เป็นฟังก์ชั่นที่ถูกต้องแน่นอน
slayton

2
@slayton: ลองใช้เครื่องมือ crunching ตัวเลขขั้นสูงที่ออกแบบมาให้มีประสิทธิภาพสุดยอดสามารถสร้างแปลงที่สวยงามพร้อมเผยแพร่ได้อย่างแม่นยำที่สุดเท่าที่จะเป็นไปได้และใช้มันเพื่อทำ ... ** การ์ตูน ** ด้วย . ขออภัยนั่นเป็นเพียงโง่ อย่างไรก็ตามมันสนุกดีซึ่งเป็นเหตุผลว่าทำไมคนส่วนใหญ่มาที่นี่ upvoted และสิ่งที่ได้คำถามเปิดใหม่ สิ่งนี้จะเป็นประโยชน์สำหรับผู้เข้าชมในอนาคตหรือไม่ อืม ... มันไม่สร้างแรงบันดาลใจ บางทีมันอาจจะเชิญบางคนให้เรียนรู้ Matlab แต่การทำงาน xkcd สไตล์อย่างถูกต้องจะต้องมีการแฮ็กและเทคนิคที่มีอืมม์ ... สงสัยอย่างน้อยที่สุด :)
rody Oldenhuis

6
@RodyOldenhuis: สำหรับฉันหนึ่งคนจะใช้กราฟเหล่านี้ในงานนำเสนอของฉัน และโดยปกติแล้วจะมี "แฮ็ก" ซึ่งคุณจะได้เรียนรู้วิธีการทำงานของสภาพแวดล้อม
Jonas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.