티스토리 뷰

matlab

단톡방 Bar Chart Race - 날짜별로 끊기

게으른 the lazy 2025. 9. 7. 03:16

 

 

지난 글에서 추가된 기능

- 함수화 하였음 (chat_race.m)

- 날짜 단위로 끊는 기능 (dayChunk)

- 여전히 개수 단위로도 끊을 수 있음 (NChunk)

- 제외할 username 지정 가능 (nameExclude)

- 어디서 끊을지 정하지 않으면 기본값은 7일 단위로 끊는 것

 

% 10일 단위로 끊기
chat_race(file, dayChunk=10)

% 1000개 단위로 끊기, "방장봇" 제외
chat_race(file, NChunk=1000, nameExclude="방장봇")

% 7일 단위로 끊기
chat_race(file)

 

 

전체 코드

 

function chat_race(file, opts)

arguments
    file
    opts.dayChunk (1, 1) = 7
    opts.NChunk (1, 1)
    opts.nameExclude = []
end

%% 텍스트 읽어오기 

fid = fopen(file);

s = fscanf(fid, '%c');
fclose(fid);

s = split(s, newline);
s = string(s);


%% 처음 등장하는 날짜 이전은 다 지우기

pattern_datestart = '^--------------- ';

while true
    if isempty(regexp(s(1), pattern_datestart, 'once'))
        s(1) = [];
    else
        break
    end
end


%% 날짜가 찾아지면, 그 줄은 지우고 다음 줄부터 닉 옆에 날짜랑 시간 쓰기

pattern_name = '^\[(.*?)\] \[오';
pattern_time = '(오전|오후) \d{1,2}:\d{2}';
pattern_date = '(?<year>\d{4})년 (?<month>\d{1,2})월 (?<day>\d{1,2})일';

for i = 1:length(s)
    tokens = regexp(s(i), pattern_date, 'names');
    username = regexp(s(i), pattern_name, 'tokens');
    if ~isempty(regexp(s(i), pattern_datestart, 'once')) && ...
            ~isempty(tokens)
        dt = join(struct2array(tokens), '-');
        s(i, :) = "";
    elseif ~isempty(username)
        s(i, 3) = regexp(s(i, 1), pattern_time, 'match', 'once');
        s(i, 1) = username;
        s(i, 2) = dt;
    else
        s(i, :) = "";
    end
end

s(s(:, 1)=="", :) = [];


%% 제외할 닉네임 제외하기

for i = 1:length(opts.nameExclude)
    s(s(:,1) == opts.nameExclude(i), :) = [];
end


%% 테이블로 만들고 datetime 추가하기 

s = table(s(:, 1), s(:, 2), s(:, 3), 'VariableNames', {'username', 'date', 'time'});

s.datetime = datetime(s.date + " " + s.time, ...
    InputFormat='yyyy-M-d a h:mm', locale='ko_KR', ...
    Format='yyyy-MM-dd HH:mm:ss');

s.date = datetime(s.date, 'InputFormat', 'yyyy-M-d');
firstday = s.date(1);


%% username 한번씩만 남기기

allNames = unique(s.username, 'stable');


%% Chunk 나누기

if isfield(opts, 'NChunk')
    iEnd = (1:ceil(height(s)/opts.NChunk))' * opts.NChunk;
    iStart = iEnd - opts.NChunk + 1;
    iEnd(end) = height(s);
    varnames = "~" + iEnd;
else
    lastday = s.date(end);
    edges = (firstday:caldays(opts.dayChunk):(lastday + caldays(opts.dayChunk)))';

    B = discretize(s.date, edges);
    iStart = find([true; diff(B) ~= 0]);
    iEnd = [iStart(2:end)-1; size(s, 1)];
    varnames = string(edges(1:end-1));
end

chunkIdx = [iStart iEnd];


%% ready, get set

raceTable = table(allNames, 'VariableNames', {'Username'});

for i = 1:size(chunkIdx, 1)
    chatCounts = countcats(...
        categorical(s.username(chunkIdx(i, 1):chunkIdx(i, 2)),...
        raceTable.Username));
    raceTable.(varnames(i)) = chatCounts(:);
end

raceTable(:, 2:end) = cumsum(raceTable(:, 2:end), 2);

if isfield(opts, 'NChunk')
    % 개수로 끊었을 때
    cuts = string(raceTable.Properties.VariableNames(2:end)');
    if opts.NChunk >= 1000
        cuts = ceil(double(cuts.extractAfter("~"))/1000);
        timeStamp = datetime(cuts, 1, 1, Format="y'k'");
    else
        cuts = ceil(double(cuts.extractAfter("~")));
        timeStamp = datetime(cuts, 1, 1, Format="y");
    end
else
    % 날짜로 끊었을 때
    dates = raceTable.Properties.VariableNames(2:end)';
    timeStamp = datetime(dates);
end

names = string(raceTable.Username);
data = table2array(raceTable(:, 2:end));

T = array2timetable(data', 'RowTimes', timeStamp);
T.Properties.VariableNames = names;


%% GO!

barChartRace(T, NumDisplay=10, NumInterp=3, ...
    Method="spline", ...
    Position=[545   446   962   420], ...
    XlabelName=sprintf("누적 채팅 건수 (%s~)", string(firstday)));

end

'matlab' 카테고리의 다른 글

pie 대신 piechart를 쓰자  (0) 2025.09.26
매트랩에서의 클로저  (0) 2025.09.19
단톡방 채팅 건수를 Bar Chart Race로 만들어보자.  (0) 2025.08.26
(펌) MATLAB vs PYTHON  (0) 2025.07.08
코랩에서 매트랩 돌리기  (0) 2025.06.29
댓글