%% 20th Anniversary - Most Active FEX Entries
% Jiro's picks this week are the following 4 entries:
% Systemic Risk by Tommaso Belluzzo
% fitVirusCOVID19 by milan batista
% spider_plot by Moses
% xiangruili/dicm2nii by Xiangrui Li
% This year was 20th anniversary of MATLAB Central, and to celebrate we held a coupld of contests, the Treasure Hunt and the Mini Hack. 5 years ago, I wrote this post to highlight the most active/interactive File Exchange entry, as part of the 15th anniversary. In this post, let's look at some of the most active and interactive File Exchange entries in the last 5 years.
%
%% Entries with most comments
% Just like last time, let's first look at the entries with the most number of comments posted in the last 5 years (Jan 2017 to Dec 2021).

load FEX2017to2021.mat addonsAfter2016 commentsAfter2016 versionsAfter2016

addonsAfter2016 = sortrows(addonsAfter2016,"NumComments","descend");

figure
bar([addonsAfter2016.NumAuthorComments(1:10), addonsAfter2016.NumUserComments(1:10)],"stacked")
title("Number of comments (since Jan 2017)")
xticks(1:10)
xticklabels(addonsAfter2016.NameShort(1:10))
set(gca,"TickLabelInterpreter","none")
legend("Author Comments", "User Comments", "Location", "northeast")

% If we look at the total number of comments, we see that the top entry is MATLAB File Association & Shortcut Fix by Patrik Forssén. In fact, this file was selected as a Pick of the Week back in 2016.
%
%% Wordcloud on comments
% We see that some entries have comments mostly from users, while others have more comments from the author of the entries, suggesting a "conversation" between the users and the author. Of course, entries with comments mostly from users are no less valuable. Doing a quick word cloud on the comments on "MATLAB File Association & Shortcut Fix" seems to show a lot of praise for the entry.

addonsAfter2016 = sortrows(addonsAfter2016,"NumComments","descend");

% Extract all comments from "MATLAB File Association & Shortcut Fix"
textData = commentsAfter2016.Comment(commentsAfter2016.AddOnUUID == addonsAfter2016.AddOnUUID(1) & ~commentsAfter2016.IsCommentByContributor);
figure
wordcloud(textData)
title("Comments: " + addonsAfter2016.Name(1))

%
%% Entries with most author comments
% Let's see which entries had many comments from authors.

addonsAfter2016 = sortrows(addonsAfter2016,"NumAuthorComments","descend");

figure
bar([addonsAfter2016.NumAuthorComments(1:10), addonsAfter2016.NumUserComments(1:10)],"stacked")
title("Number of comments (since Jan 2017)")
xticks(1:10)
xticklabels(addonsAfter2016.NameShort(1:10))
set(gca,"TickLabelInterpreter","none")
legend("Author Comments", "User Comments", "Location", "northeast")

% Very nice! These entries seem to have a nice balance between author and user comments.
%
%% Most updated entries
% How about number of updates? Entries that are frequently updated indicate that they are actively maintained by the author.

addonsAfter2016 = sortrows(addonsAfter2016,"NumUpdates","descend");
figure
bar(addonsAfter2016.NumUpdates(1:10))
title("Number of updates (since Jan 2017)")
xticks(1:10)
xticklabels(addonsAfter2016.NameShort(1:10))
set(gca,"TickLabelInterpreter","none")

%
%% Looking at a few metrics
% We already see a few entries that show up in multiple bar charts. Let's try to visualize a few of these metrics together and see which ones stand out.
% First, I'll arbitrarily choose entries that have at least 100 comments since Jan 2017.

addonsAfter2016_over100comments = addonsAfter2016(addonsAfter2016.NumComments > 100,:);
numEntries = height(addonsAfter2016_over100comments)

% 47 entries. That's a good number to work with.
% Let's calculate the ratio of author comments to all comments and sort based on the ratio. I do this, since I wanted to see which entries had a relatively large number of author comments compared to overall comments.

addonsAfter2016_over100comments.AuthorCommentRatio = addonsAfter2016_over100comments.NumAuthorComments ./ addonsAfter2016_over100comments.NumComments;
addonsAfter2016_over100comments = sortrows(addonsAfter2016_over100comments,"AuthorCommentRatio","descend");

% We will now look at the following 3 metrics:
% Number of author comments
% Ratio of author comments to overall comments
% Number of updates
% I will rank the 47 entries based on these metrics and look at a heatmap.

[~, id_author_comments] = sort(addonsAfter2016_over100comments.NumAuthorComments,"descend");
[~, id_author_ratio] = sort(addonsAfter2016_over100comments.AuthorCommentRatio,"descend");
[~, id_updates] = sort(addonsAfter2016_over100comments.NumUpdates,"descend");

rankings(id_author_comments,1) = 1:numEntries;
rankings(id_author_ratio,2) = 1:numEntries;
rankings(id_updates,3) = 1:numEntries;

heatmap(rankings,"XDisplayLabels",["Num Author Comments","Author Comment Ratio","Num Updates"],...
    "YDisplayLabels", addonsAfter2016_over100comments.NameShort)

% Here are the entries that ranked in under 10 in all three categories.

selectedEntries = addonsAfter2016_over100comments(rankings(:,1) < 10 & rankings(:,2) < 10 & rankings(:,3) < 10,:);
selectedEntries(:,["Name" "ID" "Author" "NumComments" "NumAuthorComments" "AuthorCommentRatio" "NumUpdates"])

%
%% Visualize interactions
% Let's look at the timings of the interactions in these entries. You'll notice that these interactions happen consistently, which is great to see.
% Systemic Risk
% This entry has had the highest number of updates in this time frame, which have most likely been motivated by the many comments from the users.

createTimelinePlot(1,selectedEntries,commentsAfter2016,versionsAfter2016)

% fitVirusCOVID19
% As you might expects, this one came out soon after the pandemic outbreak. You see a lot of discussions happening the first half of 2020.

createTimelinePlot(2,selectedEntries,commentsAfter2016,versionsAfter2016)

% spider_plot
% This entry has been selected as a pick of the week a couple of times in the past. The first Pick was on Oct 2019, and you can see that Moses started to increase his update frequency around that time.

createTimelinePlot(3,selectedEntries,commentsAfter2016,versionsAfter2016)

% xiangruili/dicm2nii
% The file updates for this entry have stopped, but Xiangrui continues to communicate with his uses through the comments.

createTimelinePlot(4,selectedEntries,commentsAfter2016,versionsAfter2016)

%
%% Comments
% Congratulations to these 4 entries. MATLAB Central and File Exchange exist because of the community contributions. We appreciate the discussions you have to improve the quality of the content on this site! Please tell us what you think here or leave a comment to the authors.
%
%% Helper function for creating timeline plot

function createTimelinePlot(id,selectedEntries,commentsAfter2016,versionsAfter2016)

commentsForEntry = commentsAfter2016(commentsAfter2016.AddOnUUID == selectedEntries.AddOnUUID(id),:);
x = commentsForEntry.Date;
y = 2*ones(height(commentsForEntry),1);
y(commentsForEntry.IsCommentByContributor) = 3;
versionsForEntry = versionsAfter2016(versionsAfter2016.AddOnUUID == selectedEntries.AddOnUUID(id),:);
scatter(x,y,100,"MarkerEdgeColor","none","MarkerFaceColor","blue","MarkerFaceAlpha",0.25)
ylim([0 3.5])

hold on
yline(2)
yline(3)
plot([versionsForEntry.Date, versionsForEntry.Date]',...
    [1*ones(1,height(versionsForEntry));zeros(1,height(versionsForEntry))],"r");
hold off

yticks([0.5 2 3])
yticklabels(["Updates", "User Comments", "Author Comments"])
ytickangle(60)

title([selectedEntries.Name(id) selectedEntries.Author(id)],"Interpreter","none")

end