{"id":3701,"date":"2020-05-14T07:51:38","date_gmt":"2020-05-14T11:51:38","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/?p=3701"},"modified":"2020-05-14T10:04:36","modified_gmt":"2020-05-14T14:04:36","slug":"can-contact-tracing-help-the-end-covid-19-lockdown","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2020\/05\/14\/can-contact-tracing-help-the-end-covid-19-lockdown\/","title":{"rendered":"Can Contact Tracing Help the End COVID-19 Lockdown?"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p>Since the pandemic became a global problem in March, we have been gratified <a href=\"https:\/\/www.mathworks.com\/solutions\/covid-19-research-and-development.html\">how MATLAB users have been actively contributing to the research and development related to COVID-19<\/a>.  Today's guest blogger, <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/951521\">Toshi Takeuchi<\/a>, would like to focus on one interesting area of interest in the global fight against COVID-19.<\/p><!--\/introduction--><h3>Contents<\/h3><div><ul><li><a href=\"#4afa1451-4602-490e-95e9-dcd532a06fa8\">Contact Tracing<\/a><\/li><li><a href=\"#09252280-2327-4a64-aed3-89e6ca5f9626\">John Snow<\/a><\/li><li><a href=\"#6f5c5f83-1858-4cd9-a531-379cecd824a5\">COVID-19 and Contact Tracing<\/a><\/li><li><a href=\"#4475e35c-aa3c-42fb-b48a-8a5341907178\">Gowalla Dataset<\/a><\/li><li><a href=\"#5eca3f8d-c3c8-489d-8790-17ed627357a4\">Measuring Distance is Hard<\/a><\/li><li><a href=\"#50c2ce74-cb68-4abf-bab8-87f3cf819412\">How About GPS?<\/a><\/li><li><a href=\"#131bf668-6dec-481d-b033-71ed2ecafa13\">Call to Action<\/a><\/li><li><a href=\"#2e19464f-74ff-475d-b9fb-17c0c926b5b7\">Local Functions<\/a><\/li><\/ul><\/div><h4>Contact Tracing<a name=\"4afa1451-4602-490e-95e9-dcd532a06fa8\"><\/a><\/h4><p>As authorities are exploring strategies to gradually lifting the lockdown, <a href=\"https:\/\/www.npr.org\/2020\/04\/13\/833045473\/contact-tracing-could-be-key-to-easing-social-distancing-rules\">contact tracing<\/a> is emerging as one possible piece of a comprehensive solution. Contact tracing has over 150 years of history, but it has evolved over time in response to different types of outbreaks and with availability of technology. Are we also able to make a technology-based contribution here? Let's take a look.<\/p><h4>John Snow<a name=\"09252280-2327-4a64-aed3-89e6ca5f9626\"><\/a><\/h4><p><a href=\"https:\/\/en.wikipedia.org\/wiki\/John_Snow\">Dr. John Snow<\/a> was perhaps the first person to develop a form of contact tracing. During the <a href=\"https:\/\/en.wikipedia.org\/wiki\/1854_Broad_Street_cholera_outbreak\">1854 Cholera outbreak in London<\/a>, he used data to fight against the mainstream \"miasma\" (or \"bad air\") theory of the disease to identify the true cause and helped end the outbreak. We can consider him an early pioneer of data science and epidemiology.<\/p><p>Here is the data Dr. Snow collected all by himself with pen and paper (source: <a href=\"http:\/\/blog.rtwilson.com\/john-snows-cholera-data-in-more-formats\/\">Robin's Blog<\/a>), visualized with <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/geoscatter.html\"><tt>geoscatter<\/tt><\/a>.<\/p><pre class=\"codeinput\">pumps = choleraKML2Tbl(<span class=\"string\">\"pumps.kml\"<\/span>);\r\ncholera = choleraKML2Tbl(<span class=\"string\">\"cholera_deaths.kml\"<\/span>);\r\nfigure\r\ngeoscatter(cholera.Lat,cholera.Lon,cholera.Deaths*10,<span class=\"string\">\"filled\"<\/span>)\r\nhold <span class=\"string\">on<\/span>\r\ngeoscatter(pumps.Lat,pumps.Lon,<span class=\"string\">\"filled\"<\/span>)\r\ngeoscatter(mean(cholera.Lat),mean(cholera.Lon),<span class=\"string\">\"magenta\"<\/span>,<span class=\"string\">\"filled\"<\/span>)\r\ngeoscatter(mean(cholera.Lat),mean(cholera.Lon),40000,<span class=\"string\">\"magenta\"<\/span>)\r\ntext(pumps.Lat(1),pumps.Lon(1),<span class=\"string\">\"The Broad Street Pump\"<\/span>)\r\ntitle(<span class=\"string\">\"John Snow's Cholera Map, London 1854\"<\/span>)\r\nlegend(<span class=\"string\">\"Deaths\"<\/span>,<span class=\"string\">\"Pumps\"<\/span>,<span class=\"string\">\"Centroid of Deaths\"<\/span>,<span class=\"string\">\"Location\"<\/span>,<span class=\"string\">\"southeast\"<\/span>)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/johnSnowContactTracingLS_01.png\" alt=\"\"> <p>Cholera deaths were counted and mapped to their locations. The size of a blue dot indicates the number of deaths at that location. Deaths occurred along certain routes, rather than enveloping a whole area as you would expect to see if they were caused by miasma. Dr. Snow found the Broad Street pump at the center of his map, and that led him to suspect the water supply as the possible source of the disease. Eventually, he was able to convince the local heath board to remove the handle from the pump so that people couldn't drink from that pump, and that's how he helped end the outbreak. Watch this fun YouTube video <a href=\"https:\/\/www.youtube.com\/watch?v=TLpzHHbFrHY\">the Broad Street Pump<\/a> for more details.<\/p><p><i>Note: using a circle to model the spread of the disease is more appropriate for the miasma theory. Perhaps this should be modeled as a network problem, but I kept it simple.<\/i><\/p><h4>COVID-19 and Contact Tracing<a name=\"6f5c5f83-1858-4cd9-a531-379cecd824a5\"><\/a><\/h4><p>Since location data is a critical component of contact tracing, some countries, <a href=\"https:\/\/hbr.org\/2020\/04\/how-digital-contact-tracing-slowed-covid-19-in-east-asia\">especially in East Asia<\/a>, use <a href=\"https:\/\/en.wikipedia.org\/wiki\/COVID-19_apps\">mobile apps to fight COVID-19<\/a>. This YouTube video talks about how <a href=\"https:\/\/www.youtube.com\/watch?v=BE-cA4UK07c\">South Korea, thanks to lessons from MERS outbreak, was able to ease restrictions with aggressive testing and contact tracing<\/a>. While there is criticism towards the use of technology in contact tracing due to privacy concerns or the premature easing of restrictions, we will eventually have to find a way out and we should explore all options.<\/p><p>In the US, <a href=\"https:\/\/www.wbur.org\/hereandnow\/2020\/04\/23\/cellphone-data-social-distancing-coronavirus\">researchers at the University of Texas at Austin use mobile data to understand how well social distancing is working<\/a>, by tracking visits to retail locations such as grocery stores and pharmacies, and linking these to mortality rates. <a href=\"https:\/\/en.wikipedia.org\/wiki\/Google_\/_Apple_contact_tracing_project\">Apple and Google are also working on Bluetooth-based technology with better privacy protection<\/a>. They use Bluetooth LE, which typically works in a 10-meter range, to exchange encrypted identifiers between devices that have come in contact with one another. Those keys are kept for 14 days. If a owner of such a device gets infected, then owners of the other devices are notified. This is very interesting, but is there a way for us to get a better feel for how this works with some data?<\/p><h4>Gowalla Dataset<a name=\"4475e35c-aa3c-42fb-b48a-8a5341907178\"><\/a><\/h4><p>Mobile dataset is not widely available due to privacy concerns, but I found the <a href=\"https:\/\/snap.stanford.edu\/data\/loc-gowalla.html\">Gowalla Check-in dataset<\/a> that contains anonymized user activity of a now defunct mobile app service. The service let users check into a location. This is closer in nature to the retail dataset used by the researchers at the University of Texas at Austin, not the Apple\/Google approach, but we may still learn something from it.<\/p><p>Since this is just an example, we will just use the subset of data from New York City in September 2010. <b>Let's pretend, for the sake of this example, that the data represents what people do after the lockdown is eased<\/b>, and we pick a user, 578, as the index case with diagnosis date of September 24, 2010.<\/p><pre class=\"codeinput\">nyc = loadNYCgowallaData(<span class=\"string\">\"Gowalla_totalCheckins.txt\"<\/span>);\r\ncontacts = 578; <span class=\"comment\">% index case<\/span>\r\ndiagnosisDate = datetime(<span class=\"string\">\"2010-09-24\"<\/span>,<span class=\"string\">\"TimeZone\"<\/span>,<span class=\"string\">\"America\/New_York\"<\/span>);\r\nincubationPeriod = days(14);\r\ncontactDuration = minutes(15); <span class=\"comment\">% based on check-in time<\/span>\r\nmaxDegreesOfSeparation = 2; <span class=\"comment\">% includes secondary contacts<\/span>\r\n<\/pre><p>I just picked other parameters arbitrarily, but they should be determined based on some well-established protocols set by the medical authorities.<\/p><pre class=\"codeinput\">moves = cell(maxDegreesOfSeparation + 1,1);\r\n<span class=\"keyword\">for<\/span> ii = 1:maxDegreesOfSeparation + 1\r\n    moves{ii} = getMovements(nyc,contacts,diagnosisDate,incubationPeriod,ii-1);\r\n    contacts = findContacts(nyc,moves{ii},contactDuration);\r\n<span class=\"keyword\">end<\/span>\r\nmoves = vertcat(moves{:});\r\nmoves = sortrows(moves,<span class=\"string\">\"Type\"<\/span>,<span class=\"string\">\"descend\"<\/span>);\r\nmoves.Type = renamecats(moves.Type,<span class=\"string\">\"Degree0\"<\/span>,<span class=\"string\">\"Index Case\"<\/span>);\r\n<\/pre><p>Now let's visualize the data with a <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/geodensityplot.html\"><tt>geodensityplot<\/tt><\/a>, highlighting the areas people need to avoid.<\/p><pre class=\"codeinput\">figure\r\ncolormap <span class=\"string\">hot<\/span>\r\ngeodensityplot(moves.Lat,moves.Lon,<span class=\"string\">\"FaceColor\"<\/span>,<span class=\"string\">\"interp\"<\/span>,<span class=\"string\">\"Radius\"<\/span>,500)\r\nhold <span class=\"string\">on<\/span>\r\nalphamap(normalize((1:64).^0.2,<span class=\"string\">'range'<\/span>))\r\ntitle([<span class=\"string\">\"Gowalla Check-in Dataset in NYC\"<\/span>;<span class=\"string\">\"User 578 + Direct + Secondary Contacts\"<\/span>])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/johnSnowContactTracingLS_03.png\" alt=\"\"> <p>This dataset is rather limited, but it still gives us enough to appreciate some practical technical challenges.<\/p><div><ul><li>Given the population density of Manhattan, the number of contacts is not very large, because Gowalla wasn't widely used. To make it effective for contact tracing, the app must be widely adopted. What is the minimum adoption rate needed to ensure it provides adequate protection?<\/li><li>How many days should we go back to for contact tracing? I used 14 days because that's the standard used for an incubation period. That's also what Apple and Google plan to use.<\/li><li>Typically, only people who come directly into contact with the index case (the first degree of separation) are traced but we could locate their contacts as well. When an alert goes out, who should be included?<\/li><li>People move around and visit many places in 14 days (this map only shows where they checked in). Is that because they were Gowalla users? Should we limit how much people can move around as we ease restrictions?<\/li><li>How do we define \"contact\"? I used the proximity of check-in time to keep it simple. Bluetooth LE typically works in a 10-meter range. CDC guidelines is 6 feet or 2 meters. Is 10 meters too much? It seems Apple is also planning to use the RSSI level to estimate distance.<\/li><\/ul><\/div><h4>Measuring Distance is Hard<a name=\"5eca3f8d-c3c8-489d-8790-17ed627357a4\"><\/a><\/h4><p>When it comes to using RSSI to measure distance, the MathWorks UK team successfully <a href=\"https:\/\/blogs.mathworks.com\/community\/2014\/09\/02\/expo-conversations-part-1\/\">built and demoed RFID-based people tracking system<\/a> at a MATLAB Expo several years ago. Here is the floor plan that shows the positions of the base stations (blue dots) that detected nearby RFID tags and transmitted data to a central server, stationary RFID tags around catering areas (green dots), and stationary RFID tags at respective demo areas (orange dots). Attendees also walked around with mobile RFID tags.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/signal-strength.png\" alt=\"\"> <\/p><p>When the time came to analyze the data collected from the event, we ran into a problem  &#8211; \"we had originally assumed we could use signal strength to estimate distances. However, in reality there was so much fluctuation in signal strength that you could not make a confident estimate this way\".  We eventually found a way around this problem as described in the linked post, but it was very hard.<\/p><p>We had the distance measurements for 8 base stations x 25 stationary RFID tags and the RSSI data collected from those combinations during the event. Here is the plot of RSSI against the distance. The red line represents an imaginary down-sloping line we hoped to see. As you can see, at any given distance the RSSI fluctuated so much that there was no way to derive a clear correlation between the RSSI and distance. I can't share the data, but you can read about how it was used in <a href=\"https:\/\/blogs.mathworks.com\/community\/2014\/09\/15\/expo-conversations-part-2\/\">this post<\/a>.<\/p><pre class=\"codeinput\"><span class=\"comment\">% distance ranges 0-35 meters<\/span>\r\ndisX = 0:35;\r\n<span class=\"comment\">% linear model with noise just for simplicity<\/span>\r\nRSSI = -1.6 * disX + 90 + randn(1,length(disX));\r\n<span class=\"comment\">% plot the linear model against the actual data<\/span>\r\nplotExpoData(disX,RSSI);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/johnSnowContactTracingLS_04.png\" alt=\"\"> <h4>How About GPS?<a name=\"50c2ce74-cb68-4abf-bab8-87f3cf819412\"><\/a><\/h4><p>Perhaps it is easier to determine the distance with GPS? I captured GPS data using <a href=\"https:\/\/www.mathworks.com\/products\/matlab-mobile.html\">MATLAB Mobile<\/a> in my neighborhood park. Rather than sharing my data, I would like to encourage you to <a href=\"https:\/\/www.mathworks.com\/help\/matlabmobile\/ug\/sensor-data-collection-with-matlab-mobile.html\">use your own GPS data from MATLAB Mobile because it is very easy<\/a>.<\/p><p>In order to get a distance, we need to know which points we are measuring &#8211; there is no point getting the distance between people who never actually came in contact because they were at the same point at different times. This is quite easy with <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/timetables.html\"><tt>timetable<\/tt><\/a> arrays and using the function <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/timetable.synchronize.html\"><tt>synchronize<\/tt><\/a>.<\/p><pre class=\"codeinput\">load <span class=\"string\">jpond.mat<\/span>\r\nsynched = synchronize(jpond.A(:,1:2),jpond.B(:,1:2),<span class=\"string\">\"union\"<\/span>,<span class=\"string\">\"linear\"<\/span>);\r\n<\/pre><p>Then you can use the <a href=\"https:\/\/www.mathworks.com\/help\/map\/ref\/distance.html\"><tt>distance<\/tt><\/a> and <a href=\"https:\/\/www.mathworks.com\/help\/map\/ref\/deg2km.html\"><tt>deg2km<\/tt><\/a> functions from <a href=\"https:\/\/www.mathworks.com\/products\/mapping.html\">Mapping Toolbox<\/a>. to obtain the distance.<\/p><pre class=\"codeinput\">deg = distance(synched.latitude_1,synched.longitude_1, <span class=\"keyword\">...<\/span>\r\n    synched.latitude_2,synched.longitude_2);\r\ngpsDist = deg2km(deg)*1000; <span class=\"comment\">% convert from km to meters<\/span>\r\n[minDist,minIdx] = min(gpsDist);\r\n<\/pre><p>In the following plot, you can see that two users walked around the pond in opposite directions, when they came in contact, and how far apart they were. There were two points where they got close, but the latter was the closest. Much easier than RSSI, but that's precisely why we have privacy concerns about using GPS data.<\/p><pre class=\"codeinput\">t = tiledlayout(<span class=\"string\">\"flow\"<\/span>);\r\nnexttile([2 1])\r\ngeoplot(synched.latitude_1,synched.longitude_1,<span class=\"string\">\".-\"<\/span>)\r\nhold <span class=\"string\">on<\/span>\r\ngeoplot(synched.latitude_2,synched.longitude_2,<span class=\"string\">\".-\"<\/span>)\r\ngeoplot(synched.latitude_1(minIdx),synched.longitude_1(minIdx),<span class=\"string\">\"om\"<\/span>)\r\ntext(synched.latitude_1(minIdx),synched.longitude_1(minIdx),<span class=\"string\">\"Minimum\"<\/span>, <span class=\"keyword\">...<\/span>\r\n    <span class=\"string\">\"HorizontalAlignment\"<\/span>,<span class=\"string\">\"right\"<\/span>)\r\ntitle(<span class=\"string\">\"Routes\"<\/span>)\r\nlegend(<span class=\"string\">\"A\"<\/span>,<span class=\"string\">\"B\"<\/span>,<span class=\"string\">\"Location\"<\/span>,<span class=\"string\">\"best\"<\/span>)\r\nnexttile\r\nplot(synched.Timestamp,synched.latitude_1)\r\nhold <span class=\"string\">on<\/span>\r\nplot(synched.Timestamp,synched.latitude_2)\r\nplot(synched.Timestamp(minIdx),synched.latitude_2(minIdx),<span class=\"string\">\"mo\"<\/span>)\r\ntext(synched.Timestamp(minIdx),synched.latitude_2(minIdx),<span class=\"string\">\"Minimum\"<\/span>, <span class=\"keyword\">...<\/span>\r\n    <span class=\"string\">\"HorizontalAlignment\"<\/span>,<span class=\"string\">\"right\"<\/span>)\r\ntitle (<span class=\"string\">\"Latitude x Time\"<\/span>)\r\nnexttile\r\nplot(synched.Timestamp,gpsDist)\r\nhold <span class=\"string\">on<\/span>\r\nplot(synched.Timestamp(minIdx),gpsDist(minIdx),<span class=\"string\">\"mo\"<\/span>)\r\ntext(synched.Timestamp(minIdx),gpsDist(minIdx)+80,<span class=\"string\">\"Minimum\"<\/span>, <span class=\"keyword\">...<\/span>\r\n    <span class=\"string\">\"HorizontalAlignment\"<\/span>,<span class=\"string\">\"right\"<\/span>)\r\ntitle(<span class=\"string\">\"Distance between A &amp; B\"<\/span>)\r\nylabel(<span class=\"string\">\"Meters\"<\/span>)\r\ntitle(t,[compose(<span class=\"string\">\"GPS-Based Distance Tracking, min distance %.2f meters\"<\/span>, <span class=\"keyword\">...<\/span>\r\n    minDist);compose(<span class=\"string\">\"Time at min distance %s\"<\/span>,datestr(synched.Timestamp(minIdx)))])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/johnSnowContactTracingLS_05.png\" alt=\"\"> <h4>Call to Action<a name=\"131bf668-6dec-481d-b033-71ed2ecafa13\"><\/a><\/h4><p>Through this brief survey, I hope I highlighted how contact tracing is related to data science and where MATLAB users may be able to make a contribution. Do you see other opportunities that I didn't mention? Perhaps you are already working on some of those problems? Share your ideas <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=3701#respond\">here<\/a>!<\/p><h4>Local Functions<a name=\"2e19464f-74ff-475d-b9fb-17c0c926b5b7\"><\/a><\/h4><pre class=\"codeinput\"><span class=\"keyword\">function<\/span> tbl = choleraKML2Tbl(filename)\r\n    fileID = fopen(filename);\r\n    C = textscan(fileID,<span class=\"string\">\"%s\"<\/span>);\r\n    fclose(fileID);\r\n    str = join(string(C{1}'));\r\n    coords = extractBetween(str,<span class=\"string\">\"&lt;coordinates&gt;\"<\/span>,<span class=\"string\">\"&lt;\/coordinates&gt;\"<\/span>);\r\n    coords = split(coords,<span class=\"string\">\",\"<\/span>);\r\n    coords = str2double(coords);\r\n    tbl = table;\r\n    <span class=\"keyword\">if<\/span> matches(filename,<span class=\"string\">\"pumps.kml\"<\/span>)\r\n        type = <span class=\"string\">\"Pumps\"<\/span>;\r\n    <span class=\"keyword\">elseif<\/span> matches(filename, <span class=\"string\">\"cholera_deaths.kml\"<\/span>)\r\n        type = <span class=\"string\">\"Deaths\"<\/span>;\r\n    <span class=\"keyword\">end<\/span>\r\n    tbl.Type = repmat(string(type),size(coords,1),1);\r\n    tbl.Lat = coords(:,2);\r\n    tbl.Lon = coords(:,1);\r\n    values = extractBetween(str,<span class=\"string\">\"&lt;value&gt;\"<\/span>,<span class=\"string\">\"&lt;\/value&gt;\"<\/span>);\r\n    <span class=\"keyword\">if<\/span> ~isempty(values)\r\n        values = str2double(values);\r\n        tbl.Deaths = values;\r\n    <span class=\"keyword\">else<\/span>\r\n        tbl.Deaths = zeros(height(tbl),1);\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/johnSnowContactTracingLS_02.png\" alt=\"\"> <pre class=\"codeinput\"><span class=\"keyword\">function<\/span> data = loadNYCgowallaData(gowallaDataFile)\r\n\r\n    <span class=\"keyword\">if<\/span> exist(<span class=\"string\">\"nyc.mat\"<\/span>,<span class=\"string\">\"file\"<\/span>)\r\n        load <span class=\"string\">nyc.mat<\/span> <span class=\"string\">nyc<\/span>\r\n        data = nyc;\r\n    <span class=\"keyword\">else<\/span>\r\n        opts = detectImportOptions(gowallaDataFile, <span class=\"keyword\">...<\/span>\r\n            <span class=\"string\">\"FileType\"<\/span>,<span class=\"string\">\"delimitedtext\"<\/span>,<span class=\"string\">\"TextType\"<\/span>,<span class=\"string\">\"string\"<\/span>);\r\n        opts.VariableNames = {<span class=\"string\">'User'<\/span>,<span class=\"string\">'CheckinTime'<\/span>,<span class=\"string\">'Lat'<\/span>,<span class=\"string\">'Lon'<\/span>,<span class=\"string\">'LocationId'<\/span>};\r\n        gowalla = readtable(gowallaDataFile,opts);\r\n        nycLim = [40.697,-74.079;40.819,-73.880];\r\n        nyc = gowalla(gowalla.Lat &gt;= nycLim(1,1) &amp; <span class=\"keyword\">...<\/span>\r\n            gowalla.Lat &lt;= nycLim(2,1) &amp; gowalla.Lon &gt;= nycLim(1,2) &amp; <span class=\"keyword\">...<\/span>\r\n            gowalla.Lon &lt;= nycLim(2,2),:);\r\n        nyc.CheckinTime = datetime(nyc.CheckinTime, <span class=\"keyword\">...<\/span>\r\n            <span class=\"string\">\"InputFormat\"<\/span>,<span class=\"string\">\"uuuu-MM-dd'T'HH:mm:ssZ\"<\/span>,<span class=\"string\">\"TimeZone\"<\/span>,<span class=\"string\">\"UTC\"<\/span>);\r\n        nyc.CheckinTime.TimeZone = <span class=\"string\">\"America\/New_York\"<\/span>;\r\n        data = nyc;\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeinput\"><span class=\"keyword\">function<\/span> moves = getMovements(tbl,users,endDate,lookBackPeriod,degree)\r\n    moves = cell(length(users),1);\r\n    startDate = endDate - lookBackPeriod;\r\n    <span class=\"keyword\">for<\/span> ii = 1:length(users)\r\n        moves{ii} = tbl(tbl.User == users(ii) &amp; <span class=\"keyword\">...<\/span>\r\n            tbl.CheckinTime &gt;= startDate &amp; <span class=\"keyword\">...<\/span>\r\n            tbl.CheckinTime &lt;= endDate,:);\r\n    <span class=\"keyword\">end<\/span>\r\n    moves = vertcat(moves{:});\r\n    moves.Type = repmat(<span class=\"string\">\"Degree\"<\/span> + degree,height(moves),1);\r\n    moves.Type = categorical(moves.Type);\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeinput\"><span class=\"keyword\">function<\/span> contacts = findContacts(tbl,movements,duration)\r\n    spots = movements(:,{<span class=\"string\">'LocationId'<\/span>,<span class=\"string\">'CheckinTime'<\/span>});\r\n    spots = sortrows(spots,<span class=\"string\">\"CheckinTime\"<\/span>);\r\n    users = unique(movements.User);\r\n    contacts = cell(height(spots),1);\r\n    <span class=\"keyword\">for<\/span> ii = 1:height(spots)\r\n        startTime = spots.CheckinTime(ii) - duration;\r\n        endTime = spots.CheckinTime(ii) + duration;\r\n        contacts{ii} = tbl(tbl.LocationId == spots.LocationId(ii) &amp; <span class=\"keyword\">...<\/span>\r\n            tbl.CheckinTime &gt; startTime &amp; <span class=\"keyword\">...<\/span>\r\n            tbl.CheckinTime &lt; endTime,:);\r\n    <span class=\"keyword\">end<\/span>\r\n    contacts = vertcat(contacts{:});\r\n    contacts = unique(contacts.User);\r\n    contacts(ismember(contacts,users)) = [];\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeinput\"><span class=\"keyword\">function<\/span> plotExpoData(x,y)\r\n    s = load(<span class=\"string\">\"expo.mat\"<\/span>);\r\n    expo = s.expo;\r\n    figure\r\n    plot(expo.Demos.Distance,expo.Demos.RSSI,<span class=\"string\">\".\"<\/span>)\r\n    hold <span class=\"string\">on<\/span>\r\n    plot(expo.Catering.Distance,expo.Catering.RSSI,<span class=\"string\">\".\"<\/span>)\r\n    plot(x,y,<span class=\"string\">\"mo\"<\/span>)\r\n    hold <span class=\"string\">off<\/span>\r\n    xlabel(<span class=\"string\">\"Distance\"<\/span>)\r\n    ylabel(<span class=\"string\">\"RSSI\"<\/span>)\r\n    title(<span class=\"string\">\"Base Stations vs. Stationary Tags (Demo + Catering)\"<\/span>)\r\n    legend(<span class=\"string\">\"Demo stations\"<\/span>,<span class=\"string\">\"Catering stations\"<\/span>,<span class=\"string\">\"What we wanted to see\"<\/span>)\r\n    text(5,10,<span class=\"string\">\"RSSI  vs. Distance across 8 bases x 25 anchors\"<\/span>)\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><script language=\"JavaScript\"> <!-- \r\n    function grabCode_2972360f676840a1b312351e5aa6a082() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='2972360f676840a1b312351e5aa6a082 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 2972360f676840a1b312351e5aa6a082';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2020 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_2972360f676840a1b312351e5aa6a082()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2020a<br><\/p><\/div><!--\r\n2972360f676840a1b312351e5aa6a082 ##### SOURCE BEGIN #####\r\n%% Can Contact Tracing Help End the COVID-19 Lockdown?\r\n% Since the pandemic became a global problem in March, we have been\r\n% gratified\r\n% <https:\/\/www.mathworks.com\/solutions\/covid-19-research-and-development.html\r\n% how MATLAB users have been actively contributing to the research and\r\n% development related to COVID-19>.  Today's guest blogger,\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/951521 Toshi\r\n% Takeuchi>, would like to focus on one interesting area of interest in the\r\n% global fight against COVID-19.\r\n%\r\n%% Contact Tracing\r\n% As authorities are exploring strategies to gradually lifting the\r\n% lockdown,\r\n% <https:\/\/www.npr.org\/2020\/04\/13\/833045473\/contact-tracing-could-be-key-to-easing-social-distancing-rules\r\n% contact tracing> is emerging as one possible piece of a comprehensive\r\n% solution. Contact tracing has over 150 years of history, but it has\r\n% evolved over time in response to different types of outbreaks and with\r\n% availability of technology. Are we also able to make a technology-based\r\n% contribution here? Let's take a look.\r\n%\r\n%% John Snow\r\n% <https:\/\/en.wikipedia.org\/wiki\/John_Snow Dr. John Snow> was perhaps the\r\n% first person to develop a form of contact tracing. During\r\n% the <https:\/\/en.wikipedia.org\/wiki\/1854_Broad_Street_cholera_outbreak 1854\r\n% Cholera outbreak in London>, he used data to fight against the mainstream\r\n% \"miasma\" (or \"bad air\") theory of the disease to identify the true cause\r\n% and helped end the outbreak. We can consider him an early pioneer of data\r\n% science and epidemiology.\r\n% \r\n% Here is the data Dr. Snow collected all by himself with pen and paper\r\n% (source:\r\n% <http:\/\/blog.rtwilson.com\/john-snows-cholera-data-in-more-formats\/\r\n% Robin's Blog>), visualized with\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/geoscatter.html |geoscatter|>.\r\n\r\npumps = choleraKML2Tbl(\"pumps.kml\");\r\ncholera = choleraKML2Tbl(\"cholera_deaths.kml\");\r\nfigure\r\ngeoscatter(cholera.Lat,cholera.Lon,cholera.Deaths*10,\"filled\")\r\nhold on\r\ngeoscatter(pumps.Lat,pumps.Lon,\"filled\")\r\ngeoscatter(mean(cholera.Lat),mean(cholera.Lon),\"magenta\",\"filled\")\r\ngeoscatter(mean(cholera.Lat),mean(cholera.Lon),40000,\"magenta\")\r\ntext(pumps.Lat(1),pumps.Lon(1),\"The Broad Street Pump\")\r\ntitle(\"John Snow's Cholera Map, London 1854\")\r\nlegend(\"Deaths\",\"Pumps\",\"Centroid of Deaths\",\"Location\",\"southeast\")\r\n\r\n%% \r\n% Cholera deaths were counted and mapped to their locations. The size of\r\n% a blue dot indicates the number of deaths at that location. Deaths\r\n% occurred along certain routes, rather than enveloping a whole area as you\r\n% would expect to see if they were caused by miasma. Dr. Snow found the\r\n% Broad Street pump at the center of his map, and that led him to suspect\r\n% the water supply as the possible source of the disease. Eventually, he\r\n% was able to convince the local heath board to remove the handle from the\r\n% pump so that people couldn't drink from that pump, and that's how he\r\n% helped end the outbreak. Watch this fun YouTube video\r\n% <https:\/\/www.youtube.com\/watch?v=TLpzHHbFrHY the Broad Street Pump> for\r\n% more details.\r\n% \r\n% _Note: using a circle to model the spread of the disease is more\r\n% appropriate for the miasma theory. Perhaps this should be modeled as a\r\n% network problem, but I kept it simple._\r\n%\r\n%% COVID-19 and Contact Tracing \r\n% Since location data is a critical component of contact tracing, some\r\n% countries,\r\n% <https:\/\/hbr.org\/2020\/04\/how-digital-contact-tracing-slowed-covid-19-in-east-asia\r\n% especially in East Asia>, use\r\n% <https:\/\/en.wikipedia.org\/wiki\/COVID-19_apps mobile apps to fight\r\n% COVID-19>. This YouTube video talks about how\r\n% <https:\/\/www.youtube.com\/watch?v=BE-cA4UK07c South Korea, thanks to\r\n% lessons from MERS outbreak, was able to ease restrictions with aggressive\r\n% testing and contact tracing>. While there is criticism towards the use of\r\n% technology in contact tracing due to privacy concerns or the premature\r\n% easing of restrictions, we will eventually have to find a way out\r\n% and we should explore all options.\r\n% \r\n% In the US,\r\n% <https:\/\/www.wbur.org\/hereandnow\/2020\/04\/23\/cellphone-data-social-distancing-coronavirus\r\n% researchers at the University of Texas at Austin use mobile data to\r\n% understand how well social distancing is working>, by tracking visits to\r\n% retail locations such as grocery stores and pharmacies, and linking these\r\n% to mortality rates.\r\n% <https:\/\/en.wikipedia.org\/wiki\/Google_\/_Apple_contact_tracing_project\r\n% Apple and Google are also working on Bluetooth-based technology with\r\n% better privacy protection>. They use Bluetooth LE, which typically works\r\n% in a 10-meter range, to exchange encrypted identifiers between devices\r\n% that have come in contact with one another. Those keys are kept for 14\r\n% days. If a owner of such a device gets infected, then owners of the other\r\n% devices are notified. This is very interesting, but is there a way for us\r\n% to get a better feel for how this works with some data?\r\n%\r\n%% Gowalla Dataset\r\n% Mobile dataset is not widely available due to privacy concerns, but I\r\n% found the <https:\/\/snap.stanford.edu\/data\/loc-gowalla.html Gowalla\r\n% Check-in dataset> that contains anonymized user activity of a now defunct\r\n% mobile app service. The service let users check into a location. This\r\n% is closer in nature to the retail dataset used by the researchers at the\r\n% University of Texas at Austin, not the Apple\/Google approach, but we may\r\n% still learn something from it.\r\n% \r\n% Since this is just an example, we will just use the subset of data from\r\n% New York City in September 2010. *Let's pretend, for the sake of this\r\n% example, that the data represents what people do after the lockdown is\r\n% eased*, and we pick a user, 578, as the index case with diagnosis date of\r\n% September 24, 2010.\r\n\r\nnyc = loadNYCgowallaData(\"Gowalla_totalCheckins.txt\");\r\ncontacts = 578; % index case\r\ndiagnosisDate = datetime(\"2010-09-24\",\"TimeZone\",\"America\/New_York\");\r\nincubationPeriod = days(14);\r\ncontactDuration = minutes(15); % based on check-in time\r\nmaxDegreesOfSeparation = 2; % includes secondary contacts\r\n\r\n%% \r\n% I just picked other parameters arbitrarily, but they should be determined \r\n% based on some well-established protocols set by the medical authorities.  \r\n\r\nmoves = cell(maxDegreesOfSeparation + 1,1);\r\nfor ii = 1:maxDegreesOfSeparation + 1\r\n    moves{ii} = getMovements(nyc,contacts,diagnosisDate,incubationPeriod,ii-1);\r\n    contacts = findContacts(nyc,moves{ii},contactDuration);\r\nend\r\nmoves = vertcat(moves{:});\r\nmoves = sortrows(moves,\"Type\",\"descend\");\r\nmoves.Type = renamecats(moves.Type,\"Degree0\",\"Index Case\");\r\n%% \r\n% Now let's visualize the data with a\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/geodensityplot.html\r\n% |geodensityplot|>, highlighting the areas people need to avoid.\r\n\r\nfigure\r\ncolormap hot\r\ngeodensityplot(moves.Lat,moves.Lon,\"FaceColor\",\"interp\",\"Radius\",500)\r\nhold on\r\nalphamap(normalize((1:64).^0.2,'range'))\r\ntitle([\"Gowalla Check-in Dataset in NYC\";\"User 578 + Direct + Secondary Contacts\"])\r\n\r\n%% \r\n% This dataset is rather limited, but it still gives us enough to\r\n% appreciate some practical technical challenges.\r\n% \r\n% * Given the population density of Manhattan, the number of contacts is\r\n% not very large, because Gowalla wasn't widely used. To make it effective\r\n% for contact tracing, the app must be widely adopted. What is the minimum\r\n% adoption rate needed to ensure it provides adequate protection?\r\n% * How many days should we go back to for contact tracing? I used 14 days\r\n% because that's the standard used for an incubation period. That's also\r\n% what Apple and Google plan to use.\r\n% * Typically, only people who come directly into contact with the index\r\n% case (the first degree of separation) are traced but we could locate\r\n% their contacts as well. When an alert goes out, who should be included?\r\n% * People move around and visit many places in 14 days (this map only\r\n% shows where they checked in). Is that because they were Gowalla users?\r\n% Should we limit how much people can move around as we ease restrictions?\r\n% * How do we define \"contact\"? I used the proximity of check-in time to\r\n% keep it simple. Bluetooth LE typically works in a 10-meter range. CDC\r\n% guidelines is 6 feet or 2 meters. Is 10 meters too much? It seems Apple\r\n% is also planning to use the RSSI level to estimate distance.\r\n%\r\n%% Measuring Distance is Hard\r\n% When it comes to using RSSI to measure distance, the MathWorks UK team\r\n% successfully\r\n% <https:\/\/blogs.mathworks.com\/community\/2014\/09\/02\/expo-conversations-part-1\/\r\n% built and demoed RFID-based people tracking system> at a MATLAB Expo\r\n% several years ago. Here is the floor plan that shows the positions of the\r\n% base stations (blue dots) that detected nearby RFID tags and transmitted\r\n% data to a central server, stationary RFID tags around catering areas\r\n% (green dots), and stationary RFID tags at respective demo areas (orange\r\n% dots). Attendees also walked around with mobile RFID tags.\r\n%\r\n% <<signal-strength.png>> \r\n%\r\n% When the time came to analyze the data collected from the event, we ran\r\n% into a problem  \u2013 \"we had originally assumed we could use signal\r\n% strength to estimate distances. However, in reality there was so much\r\n% fluctuation in signal strength that you could not make a confident\r\n% estimate this way\".  We eventually found a way around this problem as\r\n% described in the linked post, but it was very hard.\r\n% \r\n% We had the distance measurements for 8 base stations x 25 stationary RFID\r\n% tags and the RSSI data collected from those combinations during the\r\n% event. Here is the plot of RSSI against the distance. The red line\r\n% represents an imaginary down-sloping line we hoped to see. As you can\r\n% see, at any given distance the RSSI fluctuated so much that there was no\r\n% way to derive a clear correlation between the RSSI and distance. I can't\r\n% share the data, but you can read about how it was used in\r\n% <https:\/\/blogs.mathworks.com\/community\/2014\/09\/15\/expo-conversations-part-2\/\r\n% this post>.\r\n\r\n% distance ranges 0-35 meters\r\ndisX = 0:35; \r\n% linear model with noise just for simplicity\r\nRSSI = -1.6 * disX + 90 + randn(1,length(disX));\r\n% plot the linear model against the actual data\r\nplotExpoData(disX,RSSI);\r\n\r\n%% How About GPS?\r\n% Perhaps it is easier to determine the distance with GPS? I captured GPS\r\n% data using <https:\/\/www.mathworks.com\/products\/matlab-mobile.html MATLAB\r\n% Mobile> in my neighborhood park. Rather than sharing my data, I would\r\n% like to encourage you to \r\n% <https:\/\/www.mathworks.com\/help\/matlabmobile\/ug\/sensor-data-collection-with-matlab-mobile.html\r\n% use your own GPS data from MATLAB Mobile because it is very easy>.\r\n%\r\n% In order to get a distance, we need to know which points we are measuring\r\n% \u2013 there is no point getting the distance between people who never\r\n% actually came in contact because they were at the same point at different\r\n% times. This is quite easy with\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/timetables.html |timetable|>\r\n% arrays and using the function\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/timetable.synchronize.html\r\n% |synchronize|>.\r\n\r\nload jpond.mat\r\nsynched = synchronize(jpond.A(:,1:2),jpond.B(:,1:2),\"union\",\"linear\");\r\n\r\n%% \r\n% Then you can use the\r\n% <https:\/\/www.mathworks.com\/help\/map\/ref\/distance.html |distance|> and\r\n% <https:\/\/www.mathworks.com\/help\/map\/ref\/deg2km.html |deg2km|> functions\r\n% from <https:\/\/www.mathworks.com\/products\/mapping.html Mapping Toolbox>.\r\n% to obtain the distance.\r\n\r\ndeg = distance(synched.latitude_1,synched.longitude_1, ...\r\n    synched.latitude_2,synched.longitude_2);\r\ngpsDist = deg2km(deg)*1000; % convert from km to meters\r\n[minDist,minIdx] = min(gpsDist);\r\n%% \r\n% In the following plot, you can see that two users walked around the pond\r\n% in opposite directions, when they came in contact, and how far apart they\r\n% were. There were two points where they got close, but the latter was the\r\n% closest. Much easier than RSSI, but that's precisely why we have privacy\r\n% concerns about using GPS data.\r\n\r\nt = tiledlayout(\"flow\");\r\nnexttile([2 1])\r\ngeoplot(synched.latitude_1,synched.longitude_1,\".-\")\r\nhold on\r\ngeoplot(synched.latitude_2,synched.longitude_2,\".-\")\r\ngeoplot(synched.latitude_1(minIdx),synched.longitude_1(minIdx),\"om\")\r\ntext(synched.latitude_1(minIdx),synched.longitude_1(minIdx),\"Minimum\", ...\r\n    \"HorizontalAlignment\",\"right\")\r\ntitle(\"Routes\")\r\nlegend(\"A\",\"B\",\"Location\",\"best\")\r\nnexttile\r\nplot(synched.Timestamp,synched.latitude_1)\r\nhold on\r\nplot(synched.Timestamp,synched.latitude_2)\r\nplot(synched.Timestamp(minIdx),synched.latitude_2(minIdx),\"mo\")\r\ntext(synched.Timestamp(minIdx),synched.latitude_2(minIdx),\"Minimum\", ...\r\n    \"HorizontalAlignment\",\"right\")\r\ntitle (\"Latitude x Time\")\r\nnexttile\r\nplot(synched.Timestamp,gpsDist)\r\nhold on\r\nplot(synched.Timestamp(minIdx),gpsDist(minIdx),\"mo\")\r\ntext(synched.Timestamp(minIdx),gpsDist(minIdx)+80,\"Minimum\", ...\r\n    \"HorizontalAlignment\",\"right\")\r\ntitle(\"Distance between A & B\")\r\nylabel(\"Meters\")\r\ntitle(t,[compose(\"GPS-Based Distance Tracking, min distance %.2f meters\", ...\r\n    minDist);compose(\"Time at min distance %s\",datestr(synched.Timestamp(minIdx)))])\r\n\r\n%% Call to Action\r\n% Through this brief survey, I hope I highlighted how contact tracing is\r\n% related to data science and where MATLAB users may be able to make a\r\n% contribution. Do you see other opportunities that I didn't mention?\r\n% Perhaps you are already working on some of those problems? Share your\r\n% ideas <https:\/\/blogs.mathworks.com\/loren\/?p=3701#respond here>!\r\n\r\n%% Local Functions\r\n\r\nfunction tbl = choleraKML2Tbl(filename)\r\n    fileID = fopen(filename);\r\n    C = textscan(fileID,\"%s\");\r\n    fclose(fileID);\r\n    str = join(string(C{1}'));\r\n    coords = extractBetween(str,\"<coordinates>\",\"<\/coordinates>\");\r\n    coords = split(coords,\",\");\r\n    coords = str2double(coords);\r\n    tbl = table;\r\n    if matches(filename,\"pumps.kml\")\r\n        type = \"Pumps\";\r\n    elseif matches(filename, \"cholera_deaths.kml\")\r\n        type = \"Deaths\";\r\n    end\r\n    tbl.Type = repmat(string(type),size(coords,1),1);\r\n    tbl.Lat = coords(:,2);\r\n    tbl.Lon = coords(:,1);\r\n    values = extractBetween(str,\"<value>\",\"<\/value>\");\r\n    if ~isempty(values)\r\n        values = str2double(values);\r\n        tbl.Deaths = values;\r\n    else\r\n        tbl.Deaths = zeros(height(tbl),1);\r\n    end\r\nend\r\n%% \r\n% \r\n\r\nfunction data = loadNYCgowallaData(gowallaDataFile)\r\n\r\n    if exist(\"nyc.mat\",\"file\")\r\n        load nyc.mat nyc\r\n        data = nyc;\r\n    else\r\n        opts = detectImportOptions(gowallaDataFile, ...\r\n            \"FileType\",\"delimitedtext\",\"TextType\",\"string\");\r\n        opts.VariableNames = {'User','CheckinTime','Lat','Lon','LocationId'};\r\n        gowalla = readtable(gowallaDataFile,opts);\r\n        nycLim = [40.697,-74.079;40.819,-73.880];\r\n        nyc = gowalla(gowalla.Lat >= nycLim(1,1) & ...\r\n            gowalla.Lat <= nycLim(2,1) & gowalla.Lon >= nycLim(1,2) & ...\r\n            gowalla.Lon <= nycLim(2,2),:);\r\n        nyc.CheckinTime = datetime(nyc.CheckinTime, ...\r\n            \"InputFormat\",\"uuuu-MM-dd'T'HH:mm:ssZ\",\"TimeZone\",\"UTC\");\r\n        nyc.CheckinTime.TimeZone = \"America\/New_York\";\r\n        data = nyc;\r\n    end\r\nend\r\n%% \r\n% \r\n\r\nfunction moves = getMovements(tbl,users,endDate,lookBackPeriod,degree)\r\n    moves = cell(length(users),1);\r\n    startDate = endDate - lookBackPeriod;\r\n    for ii = 1:length(users)\r\n        moves{ii} = tbl(tbl.User == users(ii) & ...\r\n            tbl.CheckinTime >= startDate & ...\r\n            tbl.CheckinTime <= endDate,:);\r\n    end\r\n    moves = vertcat(moves{:});\r\n    moves.Type = repmat(\"Degree\" + degree,height(moves),1);\r\n    moves.Type = categorical(moves.Type);\r\nend\r\n%% \r\n% \r\n\r\nfunction contacts = findContacts(tbl,movements,duration)\r\n    spots = movements(:,{'LocationId','CheckinTime'});\r\n    spots = sortrows(spots,\"CheckinTime\");\r\n    users = unique(movements.User);\r\n    contacts = cell(height(spots),1);\r\n    for ii = 1:height(spots)\r\n        startTime = spots.CheckinTime(ii) - duration;\r\n        endTime = spots.CheckinTime(ii) + duration;\r\n        contacts{ii} = tbl(tbl.LocationId == spots.LocationId(ii) & ...\r\n            tbl.CheckinTime > startTime & ...\r\n            tbl.CheckinTime < endTime,:);\r\n    end\r\n    contacts = vertcat(contacts{:});\r\n    contacts = unique(contacts.User);\r\n    contacts(ismember(contacts,users)) = [];\r\nend\r\n%% \r\n% \r\n\r\nfunction plotExpoData(x,y)\r\n    s = load(\"expo.mat\");\r\n    expo = s.expo;\r\n    figure\r\n    plot(expo.Demos.Distance,expo.Demos.RSSI,\".\")\r\n    hold on\r\n    plot(expo.Catering.Distance,expo.Catering.RSSI,\".\")\r\n    plot(x,y,\"mo\")\r\n    hold off\r\n    xlabel(\"Distance\")\r\n    ylabel(\"RSSI\")\r\n    title(\"Base Stations vs. Stationary Tags (Demo + Catering)\")\r\n    legend(\"Demo stations\",\"Catering stations\",\"What we wanted to see\")\r\n    text(5,10,\"RSSI  vs. Distance across 8 bases x 25 anchors\")\r\nend\r\n##### SOURCE END ##### 2972360f676840a1b312351e5aa6a082\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/images\/loren\/2020\/johnSnowContactTracingLS_02.png\" onError=\"this.style.display ='none';\" \/><\/div><!--introduction--><p>Since the pandemic became a global problem in March, we have been gratified <a href=\"https:\/\/www.mathworks.com\/solutions\/covid-19-research-and-development.html\">how MATLAB users have been actively contributing to the research and development related to COVID-19<\/a>.  Today's guest blogger, <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/951521\">Toshi Takeuchi<\/a>, would like to focus on one interesting area of interest in the global fight against COVID-19.... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2020\/05\/14\/can-contact-tracing-help-the-end-covid-19-lockdown\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[66,78,89],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/3701"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=3701"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/3701\/revisions"}],"predecessor-version":[{"id":3705,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/3701\/revisions\/3705"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=3701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=3701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=3701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}