Today I’d like to introduce a guest blogger, David Garrison, who is a MATLAB Product Manager here at MathWorks.... read more >>

]]>Today I’d like to introduce a guest blogger, David Garrison, who is a MATLAB Product Manager here at MathWorks.

Hello everyone. A few months ago I announced the MATLAB Online Live Editor Challenge - a competition for students and faculty to show off their live scripts. We received a lot of great entries from universities from all over the world. Loren has been kind enought to let me use her blog to show off the winning entries.

**1st Place: Building a Forest of Trees in MATLAB**

*Ameer Hamza Khan - Hong Kong Polytechnic University*

The Forest of Trees Live Script demonstrates how to create and visualize a tree data structure in MATLAB. It demonstrates how to use classes and object-oriented programming in MATLAB to construct custom data structures and uses MATLAB graphics to visualize and explain the tree data structure. The live script also makes use of numeric sliders to allow the user to customize their tree, and see how changing each option affects the resulting tree by watching the graphical output change in response to the slider.

**2nd Place: How biodiversity is maintained in competitive ecosystems**

*Violeta Calleja Solanas - University of Zaragoza*

This MATLAB live script demonstrates two models that explain species coexistence in ecosystems: high-order interactions and sort-ranged spatial interactions. The script simulates examples of ecosystems and uses live controls to allow users to interact with the models and observe the changes. The assumptions and equations behind each model are explained in the rich text. The script also explores the power law in the distribution of communities' sizes in the simulated ecosystem.

**3rd Place: Neural Networks: The Universality Theorem**

*Mayank Jhamtani - Birla Institute of Technology and Science*

The Neural Networks: Universality Theorem project explores the Universal Approximation Theorem, which states that a single layer of "artificial neurons" can be used to approximate any function, with an arbitrarily small approximation error. This project presents an intuitive proof of the theorem by means of visual aids. The project allows the user to vary the different network parameters to approximate an arbitrary function f(x).

**4th Place: Calculate the Sag of Conductors using MATLAB**

*Timon Viola - Budapest University of Technology and Economics*

This live script shows how to simulate the sag of power line conductors. It allows users to explore the effects of different parameters, such as temperature, conductor type, and tension span, on the calculation of points of the catenary. The results are visualized in a plot.

**5th Place: Digital Processing of Electromyographic Signals for Control**

*David Leonardo Rodriguez Sarmiento: Antonio Nariño University*

This live script shows how complex mathematical calculations of digital signal processing (DSP) can be performed to infer information from biological signals (biosignals) acquired by sensors

**1st Place: The dynamics of rigid bodies system**

*Anna Sibilska-Mroziewicz - Warsaw University of Technology*

The Dynamics of Rigid Bodies Systems Live Script uses the power of live scripts to teach students the concept. It provides detailed graphics to illustrate a given system, and allows students to finalize the equations needed to model the system, providing useful, custom error messages if they model the system incorrectly. Students can adjust various values of system using numeric slider bars. The live script also makes use of the power of Symbolic Math Toolbox in its equations, including specifying units for each parameter in the system.

**2nd Place: Influence Permanent Magnet DC Motor Parameters**

*Alexander Ivanov - Skolkovo Institute of Science and Technology*

This live script explains the working principles of a PMDC motor and how it can be modeled. The transient process is calculated and plotted. The script also explores the influence of the armature resistance, armature inductance, armature inertia, magnetic flux and supply voltage on the transient process.

**3rd Place: Visualization and analysis of an Electrocardiogram Signal**

Constantino Reyes-Aldasoro - City University of London

The Electrocardiogram Live Script uses Signal Processing Toolbox to find peaks of data from an EKG and shows how to refine the peaks based on the user's data. The live script also shows how to gather data from various sources, including data from a web site, and provides some tips on visualizing complex data in MATLAB figures to help see critical regions, such as peaks, more clearly. In addition, it illustrates how to infer heart rate from the peaks of the electrocardiogram data.

Let the winners know what you think of their live scripts here.

Get
the MATLAB code

Published with MATLAB® R2018a

Today's guest blogger is Mary Fenelon, who is the product marketing manager for Optimization and Math here at MathWorks. In today's post she describes how she uses optimization to try to best the rest of the product marketing team.... read more >>

]]>Today's guest blogger is Mary Fenelon, who is the product marketing manager for Optimization and Math here at MathWorks. In today's post she describes how she uses optimization to try to best the rest of the product marketing team.

The National Football League 2018 season will soon be_ (is?)_ upon us. Several of us in the product marketing team here at MathWorks have played in an office league for the last couple of years. I don't follow the NFL very closely so I didn't think about participating until one of my fellow product marketing managers challenged me to do so by remarking that this looked like an optimization problem. That's all it took!

- This is a knockout or survivor style pool. Every week, your goal is to pick the winning team for one game. You can only choose a team once for the entire season. If your team wins or ties you move on to the next week and pick from the remaining teams. As long as you haven’t picked a losing team you can choose from the entire group of NFL teams.
- If you pick a losing team you are not out of the knockout pool. You are now restricted to picking from the teams that had a non-winning record last season. You can try to keep your streak alive, but now you have to do it with a more limited set of teams.
- Whoever is alive for the longest number of weeks wins the knockout pool. The longer you keep the knockout streak alive the bigger the knockout pool grows. It will start at 50% of the pool, and grow onward. The pot will grow until the last person has two losses. If two or more people tie, they will either split the pool or determine a final winner by a joust in the parking lot.
- After your second loss you can still win the secondary pool, which is whoever picks the most winners throughout the season. Once you’ve lost twice you can go back to picking any team as long as you haven’t already picked them. Whoever wins the knockout pool is ineligible for this prize unless there’s unforeseen circumstances (if everyone is knocked out in week 2, for example).

I could choose a team each week without considering that it would be better to choose that team further out. That myopic strategy could leave me with poor choices at the end of the season. Instead, my first strategy decision is to run an optimization each week choosing teams for all of the remaining weeks of the season but use only the choice for the current week. That way, I benefit from updated information as the season progresses while still looking at the whole schedule.

Coming up with a set of choices can be modeled as a linear assignment problem. The goal in an assignment problem is to assign workers to tasks so that the cost of completing all the tasks is minimized. Each worker can only do one task. For the NFL pool, the workers are the teams and the tasks are the weeks.

What to use for the costs of each team-to-week assignment? This choice is the second place where the art and science of modeling comes into play. Art, to think of measures, and science, to validate that the chosen measure gives the desired result. My choice is to use the win probabilities produced by fivethirtyeight.com. This article explains how they built their predictive model using the entire history of the NFL as data. With that measure, the objective is to maximize the sum of the win probabilities of the chosen teams over the entire season.

Linear assignment problems can by solved by the Hungarian algorithm. This implementation on the MATLAB File Exchange is a popular one. These problems can also be solved by the functions in Optimization Toolbox. Formulating the problem as an optimization problem gives me the option to specify additional constraints, for instance, to follow the rule that after one loss, I'm restricted to choose from the losers bracket.

**Season Data**

For this post, I'll generate some data instead of using actual NFL data. I'll use about half the teams and half as many games as the NFL.

nSeasonWeeks = 8; teams = ["Aardvarks","Bats","Cheetahs","Dragons","Emus","Foxes","Giraffes","Hippos","Ibexes","Jackals",... "Koalas","Lemurs","Monkeys","Newts","Otters","Porcupines"]'; nTeams = numel(teams);

Designate some teams as losers from the previous season for the losers bracket. Set the random seed to reproduce the same bracket each time I run the script.

rng(19); nLosers = floor(nTeams/2); idx = randperm(nTeams); losers = teams(idx(1:nLosers));

**Weekly Data**

I'll rerun the model each week, keeping track of the week of the season and which teams I already picked.

Each week I increment the week counter.

thisWeek = 2;

Each week I add the team that was chosen the previous week

```
previousPicks = ["Aardvarks"];
```

Generate the labels for the remaining weeks:

```
weeks = "week" + string(thisWeek:nSeasonWeeks)';
nWeeksLeft = nSeasonWeeks - thisWeek + 1;
```

Get the probabilities.

Here's where I would scrape a web page for predictions. Instead, I'll use a random matrix for the win probabiliites. The random values won't show the patterns one would see in real data, but they are sufficient for showing how to set up and run the optimization model. One step towards more realistic probabilities is to first generate team pairings for the games and a game schedule. This is an optimization problem in itself; for an example see scheduling the ACC basketball conference.

winProbs = rand(nTeams,nWeeksLeft);

I will use the problem-based workflow for optimization introduced in R2017b. This workflow simplifies the process of specifying and solving linear and mixed-integer linear programs, that is, optimization problems with linear constraints and objectives and with variables that can take on continuous or discrete values.

**Variables**

First, define a two dimensional optimvar, `x`, indexed by teams and weeks. The optimization solver will compute values for an `optimvar` include in an optimproblem. I make this a binary variable, that is a variable that only takes on the values of 0 and 1 with this statement:

x = optimvar('x',teams,weeks,'LowerBound',0,'UpperBound',1,'Type','integer');

In my model, a value of 1 for `x(i,j)` will mean that team `i` is chosen for week `j` and a value of 0 means it is not chosen.

To eliminate a team that's already been picked, set the upper bounds of variables corresponding to those teams to 0.

x.UpperBound(previousPicks,weeks) = 0;

**Optimization Problem and Objective**

Next, define the optimization problem and the objective to maximize the sum of the win probabilities of the chosen teams:

```
p = optimproblem;
p.ObjectiveSense = 'maximize';
p.Objective = sum(sum(winProbs.*x));
```

**Constraints**

The first constraint statement generates one constraint for each team: a team can be chosen at most once. The result is an optimconstr. Show the first constraint of each set to check the formulation as it's built.

p.Constraints.eachTeamAtMostOnce = sum(x,2) <= 1; showconstr(p.Constraints.eachTeamAtMostOnce(1))

x('Aardvarks', 'week2') + x('Aardvarks', 'week3') + x('Aardvarks', 'week4') + x('Aardvarks', 'week5') + x('Aardvarks', 'week6') + x('Aardvarks', 'week7') + x('Aardvarks', 'week8') <= 1

The second constraint statement generates one constraint for each week: a team must be choosen.

p.Constraints.mustPickOne = sum(x,1) == 1; showconstr(p.Constraints.mustPickOne(1))

x('Aardvarks', 'week2') + x('Bats', 'week2') + x('Cheetahs', 'week2') + x('Dragons', 'week2') + x('Emus', 'week2') + x('Foxes', 'week2') + x('Giraffes', 'week2') + x('Hippos', 'week2') + x('Ibexes', 'week2') + x('Jackals', 'week2') + x('Koalas', 'week2') + x('Lemurs', 'week2') + x('Monkeys', 'week2') + x('Newts', 'week2') + x('Otters', 'week2') + x('Porcupines', 'week2') == 1

**Solve**

Now solve the optimization problem. The solve function will call the mixed-integer linear programming solver, intlinprog,| b|ecause some of the optimization variables are of type integer

soln = solve(p);

LP: Optimal objective value is -6.661074. Optimal solution found. Intlinprog stopped at the root node because the objective value is within a gap tolerance of the optimal value, options.AbsoluteGapTolerance = 0 (the default value). The intcon variables are integer within tolerance, options.IntegerTolerance = 1e-05 (the default value).

**Tabulate choices**

Optimization Toolbox solvers use floating point arithmetic so it's possible that the solution values may not be integral. I want to use the values as logical indexes, so I will round them just to be sure that they are.

picks = round(soln.x); [teampicks,weekpicks] = find(picks); probpicks = find(picks); table(weeks(weekpicks),teams(teampicks),winProbs(probpicks),... 'VariableNames',{'Week','Team','WinProb'})

ans = 7×3 table Week Team WinProb _______ _________ _______ "week2" "Foxes" 0.94616 "week3" "Lemurs" 0.9943 "week4" "Bats" 0.97137 "week5" "Koalas" 0.99744 "week6" "Dragons" 0.91183 "week7" "Ibexes" 0.98344 "week8" "Hippos" 0.85654

The win probabilities will be updated on the results of the prior games as the season progresses. Maybe I don't want to value the probabilities for the end of the season as highly as those in the current week. This can be done by applying a discount factor. In the Live Script version of this post, I set the discount factor with a Live Control to make it easy to experiment with different values.

discountFactor =0.05 scalePerWeek = (1-discountFactor).^(0:nWeeksLeft-1); dProbs = winProbs.*scalePerWeek; p.Objective = sum(sum(x.*dProbs)); soln = solve(p); [teampicks,weekpicks] = find(picks); probpicks = find(picks); table(weeks(weekpicks),teams(teampicks),winProbs(probpicks),... 'VariableNames',{'Week','Team','WinProb'})

discountFactor = 0.05 LP: Optimal objective value is -5.755877. Optimal solution found. Intlinprog stopped at the root node because the objective value is within a gap tolerance of the optimal value, options.AbsoluteGapTolerance = 0 (the default value). The intcon variables are integer within tolerance, options.IntegerTolerance = 1e-05 (the default value). ans = 7×3 table Week Team WinProb _______ _________ _______ "week2" "Foxes" 0.94616 "week3" "Lemurs" 0.9943 "week4" "Bats" 0.97137 "week5" "Koalas" 0.99744 "week6" "Dragons" 0.91183 "week7" "Ibexes" 0.98344 "week8" "Hippos" 0.85654

Applying a discount factor of 5% didn't change the results.

I might want to only choose winning teams when I have no losses so that I can pick the best of the losing teams when I have to pick among them.

onlyWinners = false; if onlyWinners p.Constraints.onlyWinners = sum(x(losers,weeks),1) == 0; end

With one loss, I must pick from the losers bracket.

onlyLosers = true; if onlyLosers p.Constraints.onlyLosers = sum(x(losers,weeks),1) >= 1; showconstr(p.Constraints.onlyLosers(1)) end

x('Aardvarks', 'week2') + x('Cheetahs', 'week2') + x('Dragons', 'week2') + x('Emus', 'week2') + x('Foxes', 'week2') + x('Koalas', 'week2') + x('Newts', 'week2') + x('Otters', 'week2') >= 1

soln = solve(p); [teampicks,weekpicks] = find(picks); probpicks = find(picks); table(weeks(weekpicks),teams(teampicks),winProbs(probpicks),... 'VariableNames',{'Week','Team','WinProb'})

LP: Optimal objective value is -4.838951. Optimal solution found. Intlinprog stopped at the root node because the objective value is within a gap tolerance of the optimal value, options.AbsoluteGapTolerance = 0 (the default value). The intcon variables are integer within tolerance, options.IntegerTolerance = 1e-05 (the default value). ans = 7×3 table Week Team WinProb _______ _________ _______ "week2" "Foxes" 0.94616 "week3" "Lemurs" 0.9943 "week4" "Bats" 0.97137 "week5" "Koalas" 0.99744 "week6" "Dragons" 0.91183 "week7" "Ibexes" 0.98344 "week8" "Hippos" 0.85654

So how did I do? In both years, I was knocked out fairly early but finished at the top of the secondary pool.

Unfortunately, one player had no losses in both years so there was no secondary pool award. That player has not revealed his strategy but there is speculation that he uses an optimization model. A player with just one loss did reveal his strategy: picking the best team from fivethirtyeight.com each week. That's the myopic strategy I didn't want to use! I can see why it makes sense, though. There are about twice as many teams as games so as long as you can pick from the entire league, there should be some good picks available each week. A greedy strategy also makes sense when the predictions are changing during the season.

I'm not willing to give up on placing well in the secondary pool so I'll keep my assignment model. I can make it greedier by using a higher discount factor. Maybe I should also deal with the uncertainty in the probabilities by using data from more than one source or by using a stochastic optimization approach. Now that I have two years worth of data I can do some model validation before deciding on this year's strategy. It's time to get busy!

Do you have a better approach? Let us know your thoughts here.

Get
the MATLAB code

Published with MATLAB® R2018a

In my travels, I meet with many customers and they are always interested in learning about new MATLAB features and capabilities. One area that has a lot of interest is MATLAB app building. Many MATLAB users are interested in App Designer, GUIDE, and the future of the two app building platforms. So for this blog, I thought I would put some of those questions to Chris Portal, Development Manager for MATLAB Graphics & App Building, and David Garrison, MATLAB Product Manager.... read more >>

]]>In my travels, I meet with many customers and they are always interested in learning about new MATLAB features and capabilities. One area that has a lot of interest is MATLAB app building. Many MATLAB users are interested in App Designer, GUIDE, and the future of the two app building platforms. So for this blog, I thought I would put some of those questions to Chris Portal, Development Manager for MATLAB Graphics & App Building, and David Garrison, MATLAB Product Manager.

- What is the current state of app building in MATLAB?
- Why did MathWorks develop a whole new app building platform?
- How does App Designer compare to GUIDE?
- What does that mean for the future of GUIDE and the apps users have built with it?
- What about users who create their apps programmatically?
- What about apps that use Java extensions?
- How do users take their apps to the Web?
- How do users decide which app building platform is right for them?
- How are you building apps in MATLAB?

**CP:** Currently MATLAB offers two platforms for building apps – GUIDE and App Designer. GUIDE is an older platform that MATLAB users have been using for many years. Although users have been able to build apps of varying levels of sophistication with GUIDE, it has suffered from a number of workflow and usability issues we’ve been wanting to address for our users. Similarly, the component set it supports, which is predominantly the `uicontrol` set, is also very limited and based on some legacy technologies.

**DG:** In R2016a we introduced App Designer as our new app building platform. App Designer integrates the two tasks of building an app – laying out the visual components and programming the behavior. It has a new design canvas that makes it easier to add components and to organize them using tabs and panels. It includes a built-in editor that manages generated code for components in read-only sections and provides editable sections for user-written callback code. It also supports a new family of standard components such as edit fields, buttons, and spinners, as well as gauges, knobs, switches, and lamps for creating instrument panels.

**CP:** A major difference between GUIDE and App Designer is the technology used. GUIDE is based on Java Swing which is no longer being actively developed by Oracle. Building on it would have allowed some short-term wins, but it would not have scaled in the long-term or allowed us to offer web-based workflows for our users. App Designer is built on modern, web-based technologies such as JavaScript, HTML, and CSS, giving us a platform with the flexibility to keep up with the demands of our users and allowing apps to run on the web. Users can keep their existing Java-based apps running and choose to opt into the new platform when the time is right for them.

**DG:** When we introduced App Designer in R2016a, it offered a modern and user-friendly environment for laying out your app, which addressed several usability issues GUIDE has. However, for the first few releases, App Designer had some functional gaps with respect to GUIDE. Common components were missing, MATLAB graphics support was limited, and performance didn’t scale for large apps. With each release, we have been closing these gaps and addressing performance. As of R2018a, App Designer supports nearly all MATLAB 2D and 3D visualizations with pan, zoom, and rotate interactivity; menu support has been added as well as new tree and date picker components; and the code editor is able to scale to build large apps.

**CP:** Another notable difference is the coding model. App Designer generates a MATLAB class for the app, making it easier to program callbacks and share data between different parts of the app in a way that is less error prone than GUIDE. What this means is you no longer need to update a handles structure, or understand the subtleties of when to use guidata vs. appdata vs. UserData. New MATLAB interfaces have also been introduced which are designed specifically for each component. These new interfaces are easier to program to and improve on the older `uicontrol` component used by GUIDE.

**DG:** We know that many MATLAB users have time and intellectual property invested in GUIDE-based apps or in apps they've created programmatically. We will continue to support GUIDE and its associated components and have no current plans to deprecate or remove any of that functionality. Unlike other MATLAB transitions, GUIDE and App Designer can co-exist, which allows us and our users to work through the transition over a series of releases. Our focus right now is on enhancing App Designer to ensure it can serve the needs of MATLAB app builders and helping GUIDE users adopt it.

**CP:** Towards that end, we have released the GUIDE to App Designer Migration Tool for MATLAB in R2018a which eases the process of converting a GUIDE-based app to App Designer. The tool automatically creates an App Designer app with the same layout as your GUIDE app, applies the necessary component configurations, and copies the GUIDE callback code over. From there, you update the callback code to make it compatible with the new App Designer code format. To help users with this step, the tool generates a report that describes how to do the code updates and provides workarounds for some limitations. You can download the tool from the File Exchange on MATLAB Central or from the Add-On Explorer in the MATLAB desktop.

**DG:** We know some users choose not to use an interactive environment like GUIDE or App Designer – they prefer to create their apps programmatically in MATLAB. You can continue to hand-code your apps regardless of which component set you use, whether it’s the older `uicontrol` function, or the newer component set we’ve been expanding since R2016a.

**CP:** Some of these users have used Java Swing to extend the capabilities of their apps including the use of the `javacomponent` function to add custom components. They needed to do this to integrate components we did not support like tabs, trees, and date pickers, and to customize components beyond what was documented, including richer cell level formatting for tables. Other have used the undocumented `JavaFrame` property to do things like maximize or minimize the figure window. And in a few cases, users have leveraged Java Swing directly in order to take advantage of things like Java layout managers to build IDE-like apps. App Designer gives us a foundation to address these long-standing gaps for our users. App Designer has been adding support for missing components and enhancing existing ones. We have a number of features lined up that will help bridge the Java Swing gap, and enable all of our MATLAB users to build more sophisticated apps.

**DG:** We have been actively surveying users to understand how they are using Java to extend their apps. The feedback we hear directly impacts the team’s work. For example, in our survey on `JavaFrame` use, we discovered the number one reason for its use was to programmatically maximize or minimize the figure window. We added documented support for this in R2018a. We also added `uitree` in response to feedback from our survey on `javacomponent` use. Our plan is to have each release of MATLAB address some gap that has led users to go to Java, so we encourage users to fill out these surveys. Finally, we recognize some users may require specialized components that may be of lower priority for most app builders. In order to address this, we are also investigating ways to provide a documented solution for integrating 3rd party JavaScript components in MATLAB apps.

**DG:** There are a couple of ways to do this. One is by using MATLAB Online. MATLAB Online lets you run MATLAB in a desktop web browser from any computer that has access to the internet. MATLAB Online is available with select licenses. Check your eligibility here. You create an app using the desktop version of MATLAB and save it to your MATLAB Drive. To run the app in a web browser, use your MathWorks account to log onto MATLAB Online at matlab.mathworks.com . You can use MATLAB Drive to easily share your app with anybody else who has access to MATLAB Online.

**CP:** The other way is to use MATLAB Compiler. In R2018a, MATLAB Compiler introduced a new feature that allows you to package App Designer apps as a web app. You create your app on the desktop, package it for the web using MATLAB Compiler, and copy the compiled app to a MATLAB web app server you’ve set up, which is also provided with MATLAB Compiler. This results in a URL that can be accessed in a web browser by anyone who has access to the server. The benefit is anyone can run the app in a browser, even if they aren’t MATLAB users. This approach is ideal for sharing apps on-premise, for co-workers to access via a web browser.

**DG:** We recommend users start with App Designer for all new apps unless the app needs to run in a version of MATLAB prior to R2016a. It is the platform we are continuously enhancing and expanding with each release. We also think many users will benefit from migrating their GUIDE apps to App Designer using the migration tool that Chris mentioned. Migration will give your app a more modern look and will make it possible to deploy your app to the Web.

**CP:** Users might consider continuing to use GUIDE for the following reasons:

- The migration tool highlights a limitation that is critical to the app’s workflow and cannot be worked around.
- The app needs to run in older releases of MATLAB that predate App Designer’s release in R2016a.
- The app relies on the use of undocumented Java functionality that is not supported in App Designer.

**LS: Well, I think that's about it. Thank you both for sharing this valuable information with my readers.**

Have you tried App Designer? Let us know here.

Get
the MATLAB code

Published with MATLAB® R2018a

It wasn't until recently that I realized this functionality (memoize) was added to MATLAB in R2017a. Needless to say, the shipping function is different than the solution I presented over 10 years ago. And without the limitations that mine had (limited to elementwise functions that had a single input).

What is Memoization?

Let's Try It

Is That All?

Do You Use Memoization?

From Reference from My 2006 Post

The idea of memoization is to cache function results from specific inputs so if these same inputs are used again, the function can simply return the values computed earlier, without rerunning the computation. This can be useful if you have a function that is very expensive to compute.

Of course, if you run the memoized function a lot, it will take up increasing amounts of memory as unique inputs get added to the list, unless we do something to limit the cache size. That's what MATLAB does now with the function

As in my earlier post, let's try something simple, the function

fmem = memoize(@sin)

fmem = MemoizedFunction with properties: Function: @sin Enabled: 1 CacheSize: 10

y = fmem(pi./(1:5)')

y =5×11.2246e-16 1 0.86603br 0.70711 0.58779

So, we still get the answers we expect.

Now let's compute some more values, some already in the cache and others not.

ymore = fmem(pi./(1:10)')

ymore =10×11.2246e-16 1 0.86603 0.70711 0.58779 0.5 0.43388 0.38268 0.34202 0.30902

Again, no surprises on the out. The values are the ones we expect. I am not doing enough computation here for you to see the benefit of reduced time from caching, however.

Of course not! There are a bunch of choices you can use to control how much information gets cached, etc. Here's some links for more information.

Now let's see how this works. First, what is

fmem

fmem = MemoizedFunction with properties: Function: @sin Enabled: 1 CacheSize: 10

We see what function is being memoized, that caching is enabled, and how many distinct inputs are being cached. Since the inputs are consider collectively and I have called

Let's see what's been cached.

s = stats(fmem)

s =struct with fields:Cache: [1×1 struct] MostHitCachedInput: [1×1 struct] CacheHitRatePercent: 77.778 CacheOccupancyPercent: 40

s.Cache

ans =struct with fields:Inputs: {{1×1 cell} {1×1 cell} {1×1 cell} {1×1 cell}} Nargout: [1 1 1 1] Outputs: {{1×1 cell} {1×1 cell} {1×1 cell} {1×1 cell}} HitCount: [4 9 1 0] TotalHits: 14 TotalMisses: 4

And now let's use another input.

ysomemore = fmem(pi./-(1:12)')

ysomemore =12×1-1.2246e-16 -1 -0.86603 -0.70711 -0.58779 -0.5 -0.43388 -0.38268 -0.34202 -0.30902 ⋮

snew = stats(fmem)

snew =struct with fields:Cache: [1×1 struct] MostHitCachedInput: [1×1 struct] CacheHitRatePercent: 78.947 CacheOccupancyPercent: 40

snew.Cache

ans =struct with fields:Inputs: {{1×1 cell} {1×1 cell} {1×1 cell} {1×1 cell}} Nargout: [1 1 1 1] Outputs: {{1×1 cell} {1×1 cell} {1×1 cell} {1×1 cell}} HitCount: [4 9 1 1] TotalHits: 15 TotalMisses: 4

Now see what happens to the cached if we repeat an input.

yrepeat = fmem(pi./(1:10)')

yrepeat =10×11.2246e-16 1 0.86603 0.70711 0.58779 0.5 0.43388 0.38268 0.34202 0.30902

srepeat = stats(fmem)

srepeat =struct with fields:Cache: [1×1 struct] MostHitCachedInput: [1×1 struct] CacheHitRatePercent: 80 CacheOccupancyPercent: 40

srepeat.Cache

ans =struct with fields:Inputs: {{1×1 cell} {1×1 cell} {1×1 cell} {1×1 cell}} Nargout: [1 1 1 1] Outputs: {{1×1 cell} {1×1 cell} {1×1 cell} {1×1 cell}} HitCount: [4 10 1 1] TotalHits: 16 TotalMisses: 4

I can also clear the cache for a particular function or clear the caches for all memoized functions:

Do you ever use memoization in your code, with or without the MATLAB functions? Let us know how you do this here.

function f = memoize2(F) % one-arg F, inputs testable with == % allow nonscalar input. x = []; y = []; f = @inner; function out = inner(in) out = zeros(size(in)); % preallocate output [tf,loc] = ismember(in,x); % find which in's already computed in x ft = ~tf; % ones to be computed out(ft) = F(in(ft)); % get output values for ones not already in % place new values in storage x = [x in(ft(:).')]; y = [y reshape(out(ft),1,[])]; out(tf) = y(loc(tf)); % fill in the rest of the output values end end

and

function f = memoize1(F) % one-arg F, inputs testable with == x = []; y = []; f = @inner; function out = inner(in) ind = find(in == x); if isempty(ind) out = F(in); x(end+1) = in; y(end+1) = out; else out = y(ind); end end end]]>

I was talking with Mike, my boss, one afternoon. And we had been fiddling with some paper as we spoke. After trimming a page, we ended up with a not skinny strip of stiff paper. As Mike twisted it, we wondered if the envelope we could see was a sine... read more >>

]]>First thing, take picture to load into MATLAB.

```
imshow sinWave.png
```

Next do an eyeball experiment. I select a section of the twisted paper. And overlay a sine wave, with guessed amplitude.

hold on axis on x = [244 329]; y = [170 170]; del = diff(x); nsteps = 100; xx = x(1):del/nsteps:x(2); lenxm1 = length(xx)-1; scale = 4.0; yy1 = y(1)+scale*sin((0:lenxm1)/lenxm1*pi); yy2 = y(1)-scale*sin((0:lenxm1)/lenxm1*pi); plot(xx,yy1,'m',xx,yy2,'m') hold off axis off

Problem is, I don't know what the scale factor should be. I can try some values out. By changing the code and re-running the section. OR I can take advantage of one of the new features available in Live Scripts, a Numerical Slider control. I can find this in the Insert Gallery of the MATLAB Toolstrip.

So let's start again and see what this would look like.

imshow sinWave.png hold on x = [244 329]; y = [170 170]; del = diff(x); nsteps = 100; xx = x(1):del/nsteps:x(2); lenxm1 = length(xx)-1; scale = 7.5

scale = 7.5

yy1 = y(1)+scale*sin((0:lenxm1)/lenxm1*pi); yy2 = y(1)-scale*sin((0:lenxm1)/lenxm1*pi); plot(xx,yy1,'m',xx,yy2,'m') hold off

When you try the interactive controls in the Live Editor, you will see that the section reruns after the control is updated. A nice way to explore the consequences of specific parameter choices for your work!

Next let's see a zoomed in view.

axis([220, 350, 150 190])

Of course we could zoom interactively but since I don't feel like creating a video, I am doing it programmaticaIly instead. You can use the interactive zoom tools for plots in the Live Editor if you prefer.

My exploration by plotting doesn't prove anything, but I do think it's suggestive that a sine wave is at least a good candidate for the envelope of the twisted strip.

By the way, this is a picture of the Live Editor code with the slider in it.

I have found that the interactive tools in the Live Editor make parts of my exploratory work much more efficient and satisfying. What have you been able to do more easily with the Live Editor? Let me know here.

]]>I recently wrote about the relatively new Pause button on the Editor portion of the MATLAB Toolstrip. Let's pause again to think about how we can exploit the awesome Pause button on the toolbar.... read more >>

]]>I recently wrote about the relatively new Pause button on the Editor portion of the MATLAB Toolstrip. Let's pause again to think about how we can exploit the awesome Pause button on the toolbar.

I already told you how you might use this button, of course, while your code is running. But there's even more you can do than I mentioned earlier.

You can also

- do several related tasks,
**while the code is running**(i.e., a pause is not required)

- peek and see what's going on,
- then use
`profile on`, - continue,
- wait a bit,
- then pause again, and, finally,

- use
`profile report`

- open some other file to look at while the code is running
- set some more breakpoints
**while code is running**

and the right thing will happen. You can set the breakpoint by

- a right click of your mouse in the area in on the left in the editor that is green, then
- a breakpoint selection

What actions to you take while using the Pause button in MATLAB? Let us know here.

Get
the MATLAB code

Published with MATLAB® R2018a

For any human being love is one of the biggest source of joy, happiness...problems and puzzles. Today's guest blogger, Aldo Caraceto, one of my fellow Application Engineers from Italy, is going to convince you to approach it from a different angle.... read more >>

]]>For any human being love is one of the biggest source of joy, happiness...problems and puzzles. Today's guest blogger, Aldo Caraceto, one of my fellow Application Engineers from Italy, is going to convince you to approach it from a different angle.

I love music. One of my favourite songs is the popular Toto track *"Hold The Line"*. Very briefly, this song is about love and timing, as you may infer from the main chorus of the song: "Hold the line, love isn't always on time". Ok, it's not always on time, but can I predict when it will be? To answer this question, I've found a couple of insightful works, *"Strogatz, S.H. (1988), Love affairs and differential equations, Math. Magazine 61, 35"* and *"Eva M. Strawbridge, Romeo and Juliet, a Dynamical Love Affair"* which I've translated in MATLAB code. The mentioned papers answer a very simple question: how to express mathematically love dynamics, taking inspiration from *"Romeo & Juliet"* by W.Shakespeare. MATLAB may be a good friend to help us in examining the evolution of this relationship. An `ode23` solver has been used to solve the system of equations representing the story. The results are quite funny.

This first example examines the condition where each person’s feelings are only affected by the other. Besides, we want our Romeo not following the expected behaviour: in this case, he'll be a confused and confusing lover: the more Juliet loves him, the more he begins to dislike her, generating surprising reactions with regards to the original tragedy.

$\frac{dr}{dt} = - a \cdot j,$

$\frac{dj}{dt} = b \cdot r$

In the system of differential equations representing the phenomenon, `a` and `b` are real, positive numbers, and measured in 1/time, hence are frequencies: the bigger they are, the shorter in time will be the swing of emotions for the two lovers. In addition, just a quick summary of the variables represented in the plots:

`R(t)`= Romeo’s feelings for Juliet at time t .`J(t)`= Juliet’s feelings for Romeo at time t.`R(t), J(t) > 0`signify love, passion, and attraction.`R(t), J(t) < 0`values signify dislike.`R(t),J(t) == 0`signifies indifference.

a = 2e-1; b = 5e-1; loveRJ = @(t,y) [-a*y(2); b*y(1)];

Now, we can set the problem up, collect data, and plot results, adding some annotations:

tstart = 0; tfinal = 50; tspan = [tstart tfinal]; y0 = [-1;2]; % initial conditions [t,y] = ode23(@(t,y) loveRJ(t,y),tspan,y0); plot(t,y') ax = gca; ax.XLim = [0 50]; ax.YLim = [-3 3]; ax.XLabel.String = 'Time'; ax.YLabel.String = 'Emotions'; ax.Title.String = 'Romeo & Juliet''s relationship'; legend('Romeo','Juliet')

In our first example, we have described the story with the changing emotions felt by Romeo and Juliet as they feed on each other's passion and indifference while the time is passing by. As you know, things - and people - are never so simple. Let's try to describe the relationship between Romeo and Juliet a bit differently, trying to compare the first, simple representation of the relationship with a more complex version. Then, we'll plot them together.

The new mathematical model can be expressed as:

$\frac{dr}{dt} = a \cdot r + b \cdot j ,$

$\frac{dj}{dt} = c \cdot r + d \cdot j$

As you may notice, this time there are four parameters, because we'd like to consider also how Romeo and Juliet are influenced by their own feelings:

a = -0.15; d = 0.17; b = 0.9; c = -0.9;

We calculate the solutions for the two relationship model (you may find the model definitions at the end of the article):

```
tstart = 0;
tfinal = 50;
tspan = [tstart tfinal];
y0 = [1.00;-0.5]; % initial conditions
[t2,y2] = ode23(@(t,y) loveRJ_simple(t,y,a,d) ,tspan,y0);
[t1,y1] = ode23(@(t,y) loveRJ_ownEffect(t,y,a,b,c,d) ,tspan,y0);
```

and we plot them all on the same axis

figure ax1 = subplot(2,1,1); % simple plot plot(ax1, t1,y1') ax1.YLim = [-2 2]; ax1.XLabel.String = 'Time'; ax1.YLabel.String = 'Emotions'; ax1.Title.String = 'Romeo & Juliet''s relationship - simple'; legend('Romeo','Juliet') ax2 = subplot(2,1,2); % complex plot plot(ax2, t2,y2') ax2.YLim = [-1.5 1.5]; ax2.XLabel.String = 'Time'; ax2.YLabel.String = 'Emotions'; ax2.Title.String = 'Romeo & Juliet''s relationship - self-effect(complex)'; legend('Romeo','Juliet')

Here we've seen the impact of different models on the evolution of emotions; it looks like the chosen values tend to reduce the frequency of changes in emotions. Let's call it self-control (or selfishness).

Phase plane analysis is a very important technique to study the behavior of dynamic systems; it covers a particularly relevant role in the nonlinear case, where widely applicable methods for computing analytical solutions are not available. In a nutshell, it basically consist of drawing the derivatives of solutions against the solutions in the phase plane. The derivatives of solutions are usually drawn in form of vector fields, to emphasize how large are changes in the solutions at a specific point in the phase plane and show the trajectories of the solutions, given specific initial conditions. Therefore, by superposing the two plots, it is possible to infer how the solutions might evolve, for the purposes to build our understanding under which conditions a system might stable or not.

We start calculating the derivatives `y1'` and `y2'` for each point of the phase plane. We create a grid of points where we want to draw out plots:

y1 = linspace(-10,10,20); y2 = linspace(-10,10,20);

`meshgrid` creates two matrices: one for all the uu-values of the grid, and one for all the vv-values of the grid. Then, we consider `x1` and `x2` matrices: `x1` will contain the value of `y1'` at each uu and vv position, while `x2` will contain the value of `y2'` at each uu and vv position of our grid.

[uu,vv] = meshgrid(y2,y1); x1 = zeros(size(uu)); x2 = zeros(size(vv));

Now we compute the vector field and plot the phase portrait. Our derivatives are computed for each point (y1, y2) at `init_time = 0`, through a `for` loop. We have obtained the phase portrait.

a = -2e-1; b = 5e-1; init_time=0; loveRJ = @(t,y) [a*y(2); b*y(1)]; for i = 1:numel(uu) Yder = loveRJ(init_time,[uu(i); vv(i)]); x1(i) = Yder(1); x2(i) = Yder(2); end

Finally we compute a couple of solutions and plot them, along with the phase portrait, on the phase plane.

figure quiver(gca,uu,vv,x1,x2,'r'); xlabel('Juliet Emotions'); ylabel('Romeo Emotions'); axis tight equal; % Calculate and plot 1st Solution tstart = 0; tfinal = 50; tspan = [tstart tfinal]; y0_1 = [2;-1]; % initial conditions [t,y1] = ode23(@(t,y) loveRJ(t,y),tspan,y0_1); figure(gcf) hold on plot(y1(:,2),y1(:,1),'b') plot(y1(1,2),y1(1,1),'mo',... % starting point 'MarkerEdgeColor','k',... 'MarkerFaceColor',[.49 1 .63],... 'MarkerSize',10) plot(y1(end,2),y1(end,1),'bs',... % ending point 'MarkerEdgeColor','k',... 'MarkerFaceColor',[.49 .63 1],... 'MarkerSize',10) % Calculate 2nd Solution y0_2 = [4;1]; % initial conditions [t,y2] = ode23(@(t,y) loveRJ(t,y),tspan,y0_2);figure(gcf) plot(y2(:,2),y2(:,1),'c') plot(y2(1,2),y2(1,1),'ko',... % starting point 'MarkerEdgeColor','k',... 'MarkerFaceColor',[.49 1 .63],... 'MarkerSize',10) plot(y2(end,2),y2(end,1),'bs',... % ending point 'MarkerEdgeColor','k',... 'MarkerFaceColor',[.49 .63 1],... 'MarkerSize',10) hold off title("Two solutions plotted on vector field")

This is the first model of their relationship, just dependent on the `a` / `b` parameters, defining Romeo's / Juliet's attraction for her/his counterpart.

function dy = loveRJ_simple(t,y,a,b) dR = a*y(2); dJ = b*y(1); dy = [dR;dJ]; end

In the second model of relationship, two additional parameters appear:

`a,d`= how Romeo, Juliet are influenced by their own feelings;`b,c`= Romeo's, Juliet's attraction for her/his counterpart.

function dy = loveRJ_ownEffect(t,y,a,b,c,d) dR = a*y(1) + b*y(2); dJ = c*y(1) + d*y(2); dy = [dR;dJ]; end

Today we have taken some steps in the analysis of this ''special'' dynamic system. Others can be done, exploiting tools already available in MATLAB. For example, making the system even more realistic, using the same ODE solver would have been a good deal or would you have chosen another one and why? Do you think calculating eigenvalues would have shed some more light on your understanding of the system? How would you do it in MATLAB? Try to answer these questions and ask yourself some new ones! Let us know what you think here.

Get
the MATLAB code

Published with MATLAB® R2018a

Today I'd like to introduce a guest blogger, Stephen Doe, who works for the MATLAB Documentation team here at MathWorks. In today's post, Stephen discusses how, and why, you might want to update your code to accept string arrays as inputs.... read more >>

]]>Today I'd like to introduce a guest blogger, Stephen Doe, who works for the MATLAB Documentation team here at MathWorks. In today's post, Stephen discusses how, and why, you might want to update your code to accept string arrays as inputs.

In R2016b, MATLAB® introduced the `string` data type as a new data type for text. Each element of a string array stores a sequence of characters. You can use standard array indexing and operations on string arrays, along with string manipulation functions introduced in R2016b. Also, you can use many MATLAB functions (such as `sort` and `unique`) on string arrays.

Here's a short example. Start with some text you can store as one string--or as a string *scalar*, a term we use to describe a string array with one element. As of R2017a, you can use double-quotes to create a string. (Single-quotes still create a character vector.)

```
str = "A horse! a horse! My kingdom for a horse!"
```

str = "A horse! a horse! My kingdom for a horse!"

If you use the `split` function to split that string on space characters, then the result is a string array with nine elements. Instead of getting a cell array, you get a homogeneous array storing text--an array that has the same data type you started with. The `split` function returns the string array as a column vector. Let's reshape it as a row vector of strings for more compact display.

str = split(str); str = str'

str = 1×9 string array Columns 1 through 8 "A" "horse!" "a" "horse!" "My" "kingdom" "for" "a" Column 9 "horse!"

String arrays now provide a powerful way to deal with text in your data. As you work with your text in a string array, you never have to resort to cell arrays or curly brace indexing. I won't belabor the point, because Loren already has published some wonderful guest posts on using string arrays. If you are looking for more examples using strings, see: Introducing String Arrays, Singing the Praises of Strings, and Working with Text in MATLAB.

And of course, you can find the documentation for string arrays at Characters and Strings.

A few paragraphs ago, I said that "many" MATLAB functions now accept string arrays as inputs arguments. In fact, in a future release nearly all MathWorks® products will work with string arrays as inputs.

Here's what we mean when we say that a product "works with" string arrays as inputs:

- If an input argument can be a single piece of text, then you can specify it as a character vector
**or**as a string scalar. That is, you can use either single-quotes or double-quotes.

- If an input argument can contain multiple pieces of text, then you can specify it as a cell array of character vectors
**or**as a string array.

We're holding to this pattern in old functions where we are adding support for string arrays, and in new functions going forward. Consider the `split` function I used to split a string. It works just as well on character vectors or cell arrays of character vectors as it does on strings. (Note that functions which have always returned a character vector in previous releases, such as the `fileread` function, will continue to do so for compatibility.)

We think this approach is the most seamless way to support use of string arrays throughout our products. Our advice is to take the same approach in your own code. If you maintain code of your own, or write code for other MATLAB users, then it is to your advantage to update your code to accept string arrays as inputs, while maintaining support for the older types for storing text.

Right now, you are thinking, "Great! But how do I do that?" (Well, perhaps "great" is not the exact word that came to mind.)

To help you update your code, the R2018a documentation provides guidelines to Update Your Code to Accept Strings. You can apply these guidelines to your code now. The guidelines, and our documentation, also provide links to helper functions, such as `convertStringsToChars`, that smooth the way to accepting strings in your code.

Here is a short example that shows two ways to put these guidelines into action. I'll start with a fast and simple way that uses one of our helper functions. Then I'll follow with another way that is a little more time consuming, but is also a little more forward-looking.

Suppose this code is your original function to abbreviate the name of a city using its first three letters, making those letters uppercase. Up to now, you have specified a city's name as a character vector. For example, if the input argument is `'Boston'`, then the output argument is `'BOS'`.

function abr = abbreviateName(str) abr = upper(str(1:3)); end

If your user instead specifies the **string** `"Boston"` as the input argument, then there will be a syntax error. For a string array, the syntax `str(1:3)` means, return the first, second, and third strings as a three-element string array. But `"Boston"` all by itself is a 1-by-1 string array!

One way to support both character vectors and strings is to use the helper function `convertStringsToChars` at the beginning of the original code. `convertStringsToChars` processes an arbitrary number of input arguments and, if any of them are strings, converts them. It leaves all other data types alone.

function abr = abbreviateName(str) str = convertStringsToChars(str); abr = upper(str(1:3)); end

With the helper function, you can accept input string arrays without altering any of the code that follows. Also, the output argument type does not differ from the type returned by the original code.

A second way is to use one of the new functions for text manipulation, such as `extractBefore`. These new functions also work with character vectors and cell arrays of character vectors. And so, this new version of `abbreviateName` works the same way for inputs of any text data type.

function abr = abbreviateName(str) abr = extractBefore(str,4); abr = upper(abr); end

While this code supports both strings and character vectors, I did have to rewrite the code. Also, this code returns a string if the input is a string. The original code always returned a character vector.

Which way is the right way for you? Well, that is the "choose your own adventure" part. If you are doing a lot of work with text, then it might be time for you to do a deep dive into your code and rewrite its internals to use string arrays. If not, then use `convertStringsToChars` and minimize the pain of updating your code. On either path, look for help in our guidelines.

And if you have things to say about string arrays, or your efforts to update your own code, then let us know here.

Get
the MATLAB code

Published with MATLAB® R2018a

load creds.mat connection = twitter(consumerKey,consumerSecret,accessToken,accessTokenSecret); % 100 is the maximum number of tweets that can be pulled at a time response = search(connection,'mathworks','count',100,'lang','en')

response = ResponseMessage with properties: StatusLine: 'HTTP/1.1 200 OK' StatusCode: OK Header: [1×26 matlab.net.http.HeaderField] Body: [1×1 matlab.net.http.MessageBody] Completed: 0Each status contains information about a single tweet, such as the number of likes, when the tweet was posted, and the text of the tweet.

```
% extract each status as a string
tweets = cellfun(@(x) extractBefore(string(x.text),50), response.Body.Data.statuses);
tweets(1:3)
```

ans = 3×1 string array "listening to NPR and there's a mathworks ad? :thi" "RT @MetrowestSTEM: Thank you @MathWorks, Underwri" "Basics of eigenvalues and eigenvectors with MIT P"I was looking for tweets from a specific user. The syntax for queries that are more advanced than just a search string can be found in the Twitter documentation. This query takes the form

pctencode = @(str) replace(char(java.net.URLEncoder.encode(str,'UTF-8') ),'+','%20'); st = pctencode('from:mathworks')

st = 'from%3Amathworks'

response = search(connection,st,'count',100,'lang','en'); tweets = cellfun(@(x) extractBefore(string(x.text),50), response.Body.Data.statuses); tweets(1:3)

ans = 3×1 string array "#HardTech Is it possible to add EtherCAT Master t" "Uses #drones and kites as #renewable energy sourc" "Are We Taking the “U” Out of UX? - What is a UX d"Several months and 1033 tweets later, here is what I found.

data = readtable('someTrumpTweets.csv','TextType','string'); data = table2timetable(data);Let's take a quick peek at the numeric data.

subplot(2,1,1) plot(data.whenTweeted,[data.retweetsNo,data.likesNo],'o') legend('Number of Retweets', 'Number of Likes', 'Location','northwest') axis('tight') subplot(2,1,2) plot(data.retweetsNo,data.likesNo,'o') xlabel('Number of Retweets') ylabel('Number of Likes')It turns out that the number of retweets and number of likes are highly correlated, so we can remove the number of retweets. In R2018a, functionality to work more easily with table variables was added, including the

```
data = removevars(data,'retweetsNo');
```

I also looked at whether the time of day or day of the week had any effect on the popularity of a tweet. This was easy with the % number of tweets by hour of day byHour = groupsummary(data(:,'likesNo'),'whenTweeted','hourofday'); figure bar(0:23,byHour.GroupCount) xlabel('Hour of the Day') ylabel('Total Number of Tweets') title('Number of Tweets By Hour of the Day')After about five months of data collection, I realized that I had introduced systematic bias into my data. Tweets that are up longer have had more time to collect likes. While the Twittersphere moves quickly, I observed that weekend posts were getting a lot more likes than weekday ones. This was in part because I collected data several times a day... during the workday. This meant weekend tweets would naturally have more time to accumulate likes. Luckily, I had been stashing my raw data from each pull for reproducibility, so I was able to go back and correct this. I merged datasets, keeping likes from the latest recording available. This is not perfect, but each tweet had a few days to collect likes. After adjusting for the bias, we test for statistical significance using

data.wkEnd = isweekend(data.whenTweeted); boxplot(data.likesNo,data.wkEnd,'Labels',{'Weekday' 'Weekend'}) ylabel('Number of Likes') title('Weekday vs. Weekend')

```
% test for statistical significance
ttest2(data.likesNo(data.wkEnd),data.likesNo(~data.wkEnd))
```

ans = 1

tweetDocuments = tokenizedDocument(data.tweets,'DetectPatterns',{'at-mention','hashtag','web-address'}); tweetDeets = tokenDetails(tweetDocuments); tweetDeets(37:39,:)

ans = 3×4 table Token DocumentNumber LineNumber Type ________ ______________ __________ ___________ "Jersey" 2 1 letters "." 2 1 punctuation "#MAGA" 2 1 hashtag

```
hashtags = tweetDeets(tweetDeets.Type == 'hashtag',:);
wordcloud(hashtags.Token);
```

Not only does looking at the hashtags give us an idea of what President Trump is tweeting about (#taxreform, #fakenews, #maga), but we see some abbreviations that represent common phrases he likes to use. I used the custom function below, % make everything lower case cleanDocs = lower(tweetDocuments); % replace hashtag abbreviations with standard language cleanDocs = replaceHashtags(cleanDocs);As of R2018a, we can create bags of N-grams, which enables us to look at phrases rather than just individual words. I first did a little processing to remove some noise in the form of punctuation or words that don't tell us much about the content.

% erase punctuation cleanDocs = erasePunctuation(cleanDocs); % remove common words before analysis cleanDocs = removeWords(cleanDocs,stopWords); % remove two letter words cleanDocs = removeShortWords(cleanDocs,2); bag = bagOfNgrams(cleanDocs,'NgramLengths',3); w = wordcloud(bag);

bag2Model = bagOfWords(cleanDocs); % set seed for reproducibility rng(123) numTopics = 18; mdl = fitlda(bag2Model,numTopics,'Verbose',0); [~,topics] = max(mdl.DocumentTopicProbabilities,[],2); data.topics = topics;Not every tweet fits perfectly into one of eighteen well-defined topics. To help me label the topics, I removed some of the noise by excluding tweets classified with the lowest confidence.

```
p = mdl.DocumentTopicProbabilities; maxs = max(p,[],2); cutoff =...
quantile(maxs,.5); dataTrimmed = data(maxs>=cutoff,:);
```

for ii = 1:numTopics figure wordcloud(dataTrimmed.tweets(dataTrimmed.topics == ii)); endFinally, let's get the average number of likes by topic so we can look at the four most and least popular topics.

popCats = groupsummary(data(:,{'likesNo','topics'}),'topics','mean'); load topicNames.mat bar(topicNames, popCats.mean_likesNo); title('Popularity by Topics') ylabel('Number of Likes')In the word cloud below, the most popular topic looks like a collection of subjects that includes the FBI investigation and Hillary Clinton. The next three most popular topics are clearer: NFL players kneeling during the national anthem, fake news, and tweets about North Korea.

[~,idx] = sort(popCats.mean_likesNo,'descend'); rank = ["The" "Second" "Third" "Fourth"]; nGrams = [1 2 1 2]; for ii = 1:4 subplot(2,2,ii) bag = bagOfNgrams(cleanDocs(data.topics == idx(ii)),'NgramLengths',nGrams(ii)); wordcloud(bag); text = rank(ii) + " Most Popular, N-Grams = " + nGrams(ii); title(text) endNow let's create word clouds for the four least popular topics defined by the

nGrams = [2 2 1 2]; for ii = 0:3 subplot(2,2,ii+1) bag = bagOfNgrams(cleanDocs(data.topics == idx(end-ii)),'NgramLengths',nGrams(ii+1)); wordcloud(bag); text = rank(ii+1) + " Least Popular with N-Grams = " + nGrams(ii+1); title(text) end

function cleanTweets = replaceHashtags(tweets) % custom function used in "What are all the tweets about?" to replace % hashtags with full expressions cleanTweets = tweets; oldFN = "fakenews"; newFN = "fake news"; cleanTweets = replace(cleanTweets,oldFN,newFN); oldHH = string({"hurricaneharvey"}); newHH = "hurricane harvey"; cleanTweets = replace(cleanTweets,oldHH,newHH); oldNK = string({"northkorea" "noko"}); newNK = "north korea"; cleanTweets = replace(cleanTweets,oldNK,newNK); oldTR = string({"taxreform"}); newTR = "tax reform"; cleanTweets = replace(cleanTweets,oldTR,newTR); oldPR = string({"puerto rico"}); newPR = "puerto rico"; cleanTweets = replace(cleanTweets,oldPR,newPR); oldPRs = string({"prstrong"}); newPRs = "puerto rico strong"; cleanTweets = replace(cleanTweets,oldPRs,newPRs); oldStand = string({"standforouranthem"}); newStand = "stand for our anthem"; cleanTweets = replace(cleanTweets,oldStand,newStand); oldMAGA = string({"maga"}); newMAGA = "make america great again"; cleanTweets = replace(cleanTweets,oldMAGA,newMAGA); oldAF = string({"americafirst"}); newAF = "america first"; cleanTweets = replace(cleanTweets,oldAF,newAF); oldTC = string({"taxcutsandjobsact"}); newTC = "tax cuts and jobs act"; cleanTweets = replace(cleanTweets,oldTC,newTC); endPublished with MATLAB® R2018a ]]>

Today I’d like to introduce a guest blogger, David Garrison, who is a MATLAB Product Manager here at MathWorks. Dave will talk about an exciting new contest for students and faculty where you can win a cash prize by showing us what you can create using the Live Editor in MATLAB Online.... read more >>

]]>Today I’d like to introduce a guest blogger, David Garrison, who is a MATLAB Product Manager here at MathWorks. Dave will talk about an exciting new contest for students and faculty where you can win a cash prize by showing us what you can create using the Live Editor in MATLAB Online.

Hello everyone. Loren has been kind enough to let me use her blog to tell you about the MATLAB Online Live Editor Challenge. The challenge is open to students and faculty of any college, university, or degree-granting institution. It's an opportunity for students to win up to $750 and for faculty to win up to $1000. Simply show us how you would use the Live Editor in MATLAB Online to create a live script on a topic of interest to you.

For students, pick a topic you've learned about in a class or from a research project or pick a concept in science, engineering, math or anything else that interests you.. For faculty, select a topic in your area and show us how you would teach that topic using a live script. You can work individually or in teams and submit as many entries as you want. We’ll judge each entry on things like presentation clarity, topic uniqueness, creativity, and effective use of Live Editor features. If your entry is a winner, we'll feature your live script on our website and you'll receive a cash prize.

For the challenge you'll be using MATLAB Online to create and share your live script. With MATLAB Online, you can use the latest version of MATLAB in your a web browser without installing, configuring, or managing any software. You can check your eligibility to use MATLAB Online here.

Here's an example live script that I wrote in MATLAB Online for estimating sunrise and sunset times.

To enter the MATLAB Online Live Editor Challenge, follow these three easy steps.

- Submit an entry form. Don't forget to do that because we can't consider your entry without it.
- Use the Live Editor in MATLAB Online to create an original live script on a topic of your choice.
- Put your live script and any supporting files in a folder in MATLAB Online, then share that folder with studentcompetitions@mathworks.com.

That's all you have to do. The deadline for entries is June 29, 2018 (7 a.m. ET). For complete details and contest rules, go to www.mathworks.com/academia/student-challenge/matlab-online-live-editor-challenge.

Good luck! We look forward to seeing what you create with the Live Editor in MATLAB Online.

If you have any questions about the MATLAB Online Live Editor Challenge, please let us know here.

Get
the MATLAB code

Published with MATLAB® R2017b