Message Boards Message Boards

[WSG23] Daily Study Group: Wolfram Language Basics

Posted 2 years ago

A Wolfram U daily study group covering the implementation of Wolfram Language for tasks ranging from basic programming to video analysis begins on January 17, 2023 and runs through February 3. This study group will run on weekdays from 11:00AM–12:00PM Central US time.

This study group is an incredible way either to start learning Wolfram Language or to explore new functionality you haven't yet used. We will cover a very broad variety of topics, including but not limited to image and sound analysis, symbolics and numerics, function visualization and even cloud computation and deployment. We will even cover useful tips and tricks to help you work efficiently with notebooks!

enter image description here

No prior Wolfram Language experience is necessary. As usual, we will have questions, study materials, quizzes along the way to help you master the subject matter.

You can REGISTER HERE. I hope to see you there!

enter image description here

POSTED BY: Arben Kalziqi
164 Replies
Posted 2 years ago

Hi, I am working with signal processing forVoltage vs Timedata collected from a sensor. Its time-series plot looks as follows:

How can I extract the envelope for this signal using in-built functions in Mathematica? I tried using FindPeaks[] and EstimatedBackgroun[] functions, but they are not giving me the correct amplitude extracted waveform.

Thank you for your time.

POSTED BY: Shruti Vaidya

Hi everybody—we're granting an extension for quiz submissions for this certification through the end of this week (Friday, February 17). For people who earn this certification, we have new certificate links that we'll be sending out soon which include sharable credentials.

POSTED BY: Arben Kalziqi

Hi everybody! We'll be starting the new one-week study group series that Abrita mentioned in just a few minutes today:

Wolfram Language Certification Prep

Today will be a quick overview of the language, and will very speedily cover some of the certification-relevant ideas from the study group that you all attended. We'll get into more specific stuff in the coming days!

POSTED BY: Arben Kalziqi

Hi Arben,

Can I still add a question? I've started to play around with image processing. Now I'm confused by the output of ImageData and PixelValue. For a color image, I'd expect a list of 3 values for each pixel of the image. However, in the attached notebook, I get 4! What is the extra 1.?

Cheers, Jörn

POSTED BY: Jörn Kersten

Hi Jörn—yes, feel free to :). The fourth value is opacity. You can strip this out or modify it to suit your needs; RGBColor and Image both are happy to accept either 3 or 4 inputs of this sort.

POSTED BY: Arben Kalziqi

Are you planning to take the Wolfram Technology Certified Level I exam? If yes, feel free to join our Wolfram Language Certification Prep study group beginning Monday.

Hello Abrita Chakravarty.

I’m guessing the discussion group hasn’t been created yet, as the link in your post doesn’t seem to work. :-/

(If this was advertising a discussion group…could also be advertising the “class”).

POSTED BY: J. Leko

Link has been fixed.

Thanks for noticing, J.!

POSTED BY: Arben Kalziqi
Posted 2 years ago

Can I express a recurrence expression (and invoke RSolve) using functional programming syntax? I was looking back over the presentation on Symbolics and it didn't talk about that. Could you show how the Fibonacci number example this way? I'll see if I can answer my own question in the mean time...

POSTED BY: Phil Earnhardt

Hey phil—sorry for the late response. You can indeed do this, and you can massively speed it up (at the cost of memory usage, so it depends on your particular case) by using memoization. See here for the prototypical example.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Any way to tell if our quizzes are done or accepted? Completed all three but other than the screen saying I passed nothing else seems to have happened.

POSTED BY: Daniel Morey

During her concluding remarks for the Tips & Tricks session, I believe Cassidy mentioned that if you see the grading screen, then the score has been submitted.

POSTED BY: J. Leko

Once again, J. has the right of it. If you see the screen, you should be good to go. When we send out certificates a little while after the due date has passed, if you haven't gotten anything when you expect you should have, you can email us and we'll personally look into it for you.

POSTED BY: Arben Kalziqi

Regarding quizzes, do you receive the scores from quizzes downloaded and scored that way? As you know users don't receive any other acknowledgment. (An email acknowledgment would be a good enhancement.) Thanks again.

POSTED BY: Jonathan Ansell

Hi Arben, I haven't heard anything re the quizzes aside from the fact that I received well over 60% on each of the 3. I did the quizzes by downloading them and getting a score. I assume those get to you but wanted to be sure. Also when is the ETA on the certificate? thanks. Jon

POSTED BY: Jonathan Ansell

Hi Jon—as long as you got a score shown to you when submitting your answers, we should have your scores submitted. It's best to just do the quizzes in your browser, I think, but that just seems to reduce the incidence of buggy behavior (since you can't edit those notebooks, whereas downloaded ones can be accidentally modified et c.).

POSTED BY: Arben Kalziqi
Posted 2 years ago

None of my shortcuts for the mathematical notations work in neither Microsoft Edge, nor Chrome, with Wolfram One. How can I change that?

POSTED BY: Updating Name

I'm guessing you mean things like pretty printing for powers and quotients. This, I suspect, is just due to what browsers are allowed to do with "ctrl" keyboard shortcuts, but I'm not positive. I've added this to the above question about bracket auto-completion.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Is there autocomplete for the squared brackets [ ], curly braces { }, and parenthesis ( ) in Wolfram One? I am lost in the brackets.

POSTED BY: Alex Kuznetsov

Hi Alex—on my end, it does look like the cloud notebook interface doesn't support autocompleted brackets. I've asked to see if this is in the plans or if it's somehow unfeasible given the way cloud notebooks work, and will update you here if I hear back.

In the meantime, here's my guide:

  • [Square brackets] are only ever used for functions. Whether it's Sin[x] or HermiteH[n,x] or myCoolFunc[s,t,u] or even StringRiffle@RandomSample@StringSplit@#&[someString], square brackets are used to feed arguments to functions.

  • {Curly braces} are only ever used for lists. It doesn't matter whether it's {1,2,3} or {{a,b},{c,d},{e,f}} or {{1,2,3},{a,b},Pi}, that's where curly braces are used.

    • Note that lists can be inputs to functions, though, so you could see: Plot[{Sin[x],Cos[x]},{x,0,2Pi}]. None of the "rules" have been broken here; the functions Plot, Sin, and Cos still take their arguments in square brackets, it's just that the first argument of Plot can be a list of functions to plot and the second is (generally) a list specifying the variable and its bounds.
  • (Parentheses) are used for mathematical or "order of operations" grouping. You might see them in (a+b)/c or (a+b)^c or otherwise, but they're always used for operational grouping. You will never, ever see Sin(x) or (1,2,3).

POSTED BY: Arben Kalziqi

Noting here that cloud notebooks currently do not support this sort of auto-completion, but it is explicitly on our "to-do" list. As for keyboard shortcuts, I can confirm that it is indeed tricky because browsers intercept keyboard presses like ctrl and limit our ability to implement them for our own shortcuts.

POSTED BY: Arben Kalziqi

And finally a Mathematica question: could you explain the similarities/differences of With and ReplaceAll? When should one use With[{x=a},...] and when use a replacement /. x-> a ?

POSTED BY: Richard Laugesen

Richard,

From what I can tell, With[] is useful for situations where you want local declarations. The “See Also” section of the With documentation, for example, it references functions like Module, and Block as well as ReplaceAll. From my previous experience, ReplaceAll is the more general and widely used function.

POSTED BY: J. Leko

Hi J.—completely agree with your understanding. If there's some chunk of code (of arbitrary length and line count) for which you want to locally set some values to some given constants, With is the best choice for that. ReplaceAll is much more general and never performs any Set operation (i.e. it never sets a symbol to a particular value), it merely replaces some instance of a pattern with some other expression.

That may seem overly general, but remember that even blah/.{a->b} is a replacement rule looking for a simple pattern—the appearance of a at all—so that it can replace it with b.

POSTED BY: Arben Kalziqi

And when I post a comment (like the previous one), I get taken back to the middle of the thread. Why?! Is it a browser issue (Safari on a Mac) or a "feature" of the thread?

POSTED BY: Richard Laugesen

Feedback on the community thread - it's rather annoying that when I click on the daily link to join the thread, I'm taken to the top (oldest posts) rather than the bottom (newest posts). Please fix!

POSTED BY: Richard Laugesen
Posted 2 years ago

I noticed that it takes minutes (!!!) for the body of older messages to all render themselves. Until that's done, the display of the discussion jumps around. In general, I'd say that the forums here don't scale well. They seem to work quite well on topics announcing something -- with a small number of messages. Discourse and Discord are excellent systems for group discussion: they provide a bunch of filters. Among other things, they jump straight to new comments in discussions. Wolfram's forte is computation, visualization, etc. -- computation for the masses! Online chats are not their thing. OTOH, what they have works kinda OK. I think it's going to be a tough sell to convince them to move to one of those responsive modern chat systems.

Stephen noted in his personal blog:

The three main applications I use all day are Wolfram Desktop, a web browser, and email. My main way of working is to create (or edit) Wolfram Notebooks. Here are a few notebooks I worked on today [...]

Everything is in Wolfram Notebooks! Everything! Notes, Todos, personal existence system, corporate management, source code, presentation slides, etc. Stephen's blog entries are just an export from a Notebook. He says he's created over a hundred thousand (!!!) notebooks, and can find the correct old one in a ridiculously small amount of time. And all of them are backwards compatible (!!!) to the original Theo Gray Notebooks ~35 years ago. Very few software systems live that long; I don't know of anyone that managed #!$$ backwards compatibility back to Day 1.

That's extraordinary. It took tremendous amounts of leadership, vision, and just plain stubbornness to pull that off. This company dogfoods their software like nobody else. The downside is that their DNA strongly resists any change to what they've got here. Don't hold your breath for any change.

POSTED BY: Phil Earnhardt

Thanks for the comments, y'all. The Community team has seen them, and while certain things are indeed a bit set in stone, there are other things which aren't and can hopefully be addressed now that the team knows about them. (This is a comparatively very active thread, and some of these issues—as you note—don't really manifest in smaller threads.)

POSTED BY: Arben Kalziqi

Thank you for your feedback; it is much appreciated. We are constantly working on trying to resolve these issues.

POSTED BY: EDITORIAL BOARD
Posted 2 years ago

What part of the code in the Wolfram kernel is running on CPUs, GPUs, and Neural Engines?

My interest is on Apple's current hardware. Since the announcement of M1 chips, Apple has presented an extremely attractive architecture for offloading tasks to GPUs and their Neural Engine. Their uniform memory model means all of those processing units can access any data in RAM. Their uniform architecture spanning iPhones, iPads, laptop PCs, to desktop PCs means code can be developed and tested anywhere and then run on big systems.

Maybe most importantly, Stephen Wolfram has close ties with Apple. Stephen met Steve Jobs in 1987. The NeXT computer was bundled with the first edition of Mathematica. According to Wolfram, Steve Jobs was the person who suggested the name "Mathematica". In this 2019 blog post, Stephen notes that he uses a D700 Mac Pro -- the cylindrical Mac with massive cooling fans -- for his home office computer. I'd give high odds that he has moved on to a Mac Studio: probably one with a 20-core CPU, a 64-core GPU, and a 32-core Neural Engine. Besides the massive power of this machine, that machine is quiet enough without having to put the machine in a sound closet. I cannot imagine that Stephen would have all those shining processors sitting there and doing nothing for him would be a very strong pull.

When we were discussing functional programming, Arben noted that the "&" is the cue to the front end to compile the program. If the capabilities were there, it seems that the compilation directive could just as well be generating Neural Engine code.

One less speculative question: what is Wolfram doing these days with artificial restrictions on the number of [plain old] CPUs that can be used in an operation? A few years ago, I remember there were restrictions of 4 or 8 CPUs -- maybe a license to raise the limits on that. Now that multiprocessor is the norm (and many-multiprocessors are widely available), has Wolfram eased those restrictions?

This week, Arben commented that using functional code could have a huge impact on the efficiency of the operation. My ears perked up at that point. Despite these massively powerful chips, efficiency will always matter. Thank you.

POSTED BY: Phil Earnhardt
Posted 2 years ago

I ran across a bug when working on Quiz 3. I downloaded the quiz and opened it in Mathematica. When I opened the quiz notebook in Mathematica, all of the quote marks had been stripped out of the four possible answers to the questions. I didn't notice that the text of the quiz had changed. I went back to Quiz 1. The same thing happened, but there were almost no quote marks in the answers of that quiz. One I found was on the fourth answer to Q10 on Quiz 1:

enter image description here

I was going a bit crazy until I noticed the missing quote marks in the notebook questions in the Mathematica window. I didn't notice the quote-stripping when I did Quiz 1. One non-standard thing that could possibly be related to the bug: I'm running Mathematica 12.2.0.0 on my computer.

POSTED BY: Phil Earnhardt

How would I select from the list of Astronomical Observatories entities in Wolfram database only those that are located in the US? I've seen Select, Containsonly, Query and other functions but not sure which one to use or works best in these cases. I've pulled the data into an Association table. Thanks.

POSTED BY: Jonathan Ansell

Hi Jonathan! Each of these entities should have a property corresponding to location, and you can then use Select to get what you want. Looking now (with EntityProperties["AstronomicalObservatory"]), I see that there are a few different properties that relate to position, with one of them explicitly being "country". So:

observatories = EntityList["AstronomicalObservatory"];
observatoriesUS = 
 Select[observatories, #["Country"] == 
    Entity["Country", "UnitedStates"] &]

This isn't super fast because we need to query this huge list of observatory entities (1407 of them) for their countries—and Select does this one by one—but I expect that you could speed it up if you were doing something where speed is more important.

Get all of the countries at once, and extract their names as simple strings:

allCountries=EntityValue[EntityProperty[observatories,"Country"],"Name"];

Now, we can use Pick to quickly pick out the elements according to a test value (in this case, the test is just: "is the element 'United States'?"):

observatoriesUS = Pick[observatories, allCountries, "United States"]

Confirm that this worked:

GeoListPlot[observatoriesUS,GeoRange->"World"]

EDIT: While trying this out, I realize that my initial answer with Select actually doesn't work. While == works to compare most expressions, it doesn't work for entities exactly—basically, if you do have two equivalent entities, it will return True—but if you try and compare, say, the US and Japan, it returns unevaluated. This causes problems for Select, I think—so, using the lessons from the second solution, I think this is optimal in terms of simplicity and performance:

observatoriesUS2 = 
 Select[observatories, 
  EntityValue[#["Country"], "Name"] == "United States" &]

The key in either case is that it's very easy to compare two strings and instantly get back True/False!

POSTED BY: Arben Kalziqi
Posted 2 years ago

It would be nice to have your "Yucko Tea" tiny video sample in the downloads dir, or a URL to the video.

POSTED BY: Phil Earnhardt

Yucko coffee, as it were :). hoffmann_ohno.mp4 has been added to the Sample Data folder!

POSTED BY: Arben Kalziqi

I have a function f(x,y) defined on a set E={(x,y): 0<x<1,0<y<1 and 0<y<g(x)}, where g(x) is some given function. I want to plot the subset of E where f<0 and its complementary subset where f>0, colored red and blue respectively. This can be done using RegionPlot to generate each region:

RegionPlot[{0 < y < g[x] && f[x, y] < 0,  0 < y < g[x] && f[x, y] > 0}, {x, 0, 1}, {y, 0, 1}, PlotStyle -> {Red, Blue}]

The difficulty is that the function f(x,y) is quite time-consuming for Mathematica to evaluate (it depends on finding eigenvalues of a differential equation on an interval of length x involving a parameter y) and so I want to avoid evaluating f(x,y) twice at each point, which my code is presumably doing. Is there a way to make the code more efficient, for plotting a region and its complement?

POSTED BY: Richard Laugesen

Hi Richard—really lovely question. I think in this case you'd want to rewrite it such that the f[x,y] appears only once, like you suggest. How to do that, though? Look at the argument:

{0 < y < g[x] && f[x, y] < 0, 0 < y < g[x] && f[x, y] > 0}

We need to find a way to take this piece and rewrite it more simply. I think that having the explicit function (even if it's nasty) would be helpful here, but here's one suggestion:

regionLister[x_, y_] := 
 With[{fVal = f[x, y], gVal = g[x]}, {0 < y < gVal && fVal < 0,
   0 < y < gVal && fVal > 0}]

RegionPlot[Evaluate@regionLister[x, y], {x, 0, 1}, {y, 0, 1}, 
 PlotStyle -> {Red, Blue}]

Basically, I make a new function which, when fed x and y, computes g[x] and f[x,y] once, then creates the list of boolean conditions for that point pair using those computed values. Because the Plot family works by plugging in points in the appropriate domain, it will feed those points to regionLister and get back a result {boole1,boole2}, just like in your example. I used Evaluate to force evaluation so that these points are understood to be a list and show up with different colors.

Without your exact functions, I can't confirm that this works, but it either should work or be close to working.

One simpler option—if acceptable—is to use the PlotPoints option to lower the number of points used to generate the plot.

POSTED BY: Arben Kalziqi

Thank you, I will try this out!

POSTED BY: Richard Laugesen

Let me know how it works! I'm interested in the problem, so keep me updated and we can get into more details if this ends up not working as expected.

POSTED BY: Arben Kalziqi

Hi!

Many Mathematica functions work just as well on lists as on numbers, although the documentation does not say so explicitly. I've just noticed this for Rationalize:

Rationalize[x]
converts an approximate number x to a nearby rational with small denominator.

Although it says "number", something like Rationalize[{2.5,4.5}] works perfectly fine. This is great, of course, but I presume not all functions are that flexible. Hence the question: how do I find out what exactly a function expects as input? Other than trial and error, that is. ;-)

Cheers, Jörn

POSTED BY: Jörn Kersten

Rationalize is working on numbers here, it's just that it can work on (nested) lists of numbers as well. This comes from an attribute of the function called "listability"; you can check these attributes for any given function func by evaluating Attributes[func]. If you see Listable listed among the attributes, you can use the function on a (nested) list without needing to use Map.

https://reference.wolfram.com/language/ref/Listable.html

POSTED BY: Arben Kalziqi
Posted 2 years ago

Hi Arben

Why is Listable not an attribute for Rationalize?

Attributes[Rationalize]
(* {Protected} *)
POSTED BY: Rohit Namjoshi

You know, that's a great question :|. I don't see why it shouldn't have that attribute, so I've asked internally to see if I can get some clarification.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Hi Jörn

To get a list of all functions that have the Listable attribute

EntityList@EntityClass["WolframLanguageSymbol", {"Attributes" -> "Listable"}] // 
CanonicalName

Rationalize is not in the list for some reason. Neither is CanonicalName though clearly, it is Listable as Map was not used in the code above.

POSTED BY: Rohit Namjoshi

Hi Rohit, hi Arben!

Thanks, this is really useful!

Another function that happily works on lists but doesn't have the Listable attribute is SetPrecision. Very strange.

I also find it unfortunate that the documentation is inconsistent in this regard.

  • For some functions (e.g., CanonicalName), the use on lists is given explicitly in the short documentation (the one obtained with ?CanonicalName).
  • For some functions (e.g., Attributes), the "Details" section in the Documentation Center explicitly states the attributes.
  • Finally, for some functions (e.g., Rationalize), the documentation doesn't mention listability at all.

Looks like a nice cleanup project for an intern. :-)

Cheers, Jörn

POSTED BY: Jörn Kersten

I'm back, and this prompted some interesting discussion. In short: my understanding of listability was incorrect. Slightly less short: the name "Listable" is a V1 thing and thus is a little bit historically misleading, and might have been called "Threadable" were it introduced in the most recent version.

The idea is that if f is listable, f[{a,b,c}] should evaluate to {f[a],f[b],f[c]}, for example—i.e. it should give what Thread[f[{a,b,c}]] gives. This jives with what I said before, but the difference is in the treatment of (e.g.) f[{1,2},{3,4}], which returns {f[1,3],f[1,4]} (i.e. the result, again, of Thread[f[{1,2},{3,4}]]). My understanding of "listability" was really an emergent consequence of the underlying behavior rather than a correct understanding of what was really going on.

POSTED BY: Arben Kalziqi

Interesting Arben, Then how does Thread[] differ from Map[], and MapThread[]? There seems to be a great deal of overlap (and confusion!) between these functions. :-)

POSTED BY: J. Leko

Hi J.—now that you mention it, I forgot to cover that in the review session like I had said I would, didn't I? My apologies. Let's do it now:

  • Thread is pretty extensible, but—for me—it's a little bit haphazard/ad hoc compared to its compatriots Map and MapThread, which are much more structured.
    • Thread[f[{a,b,c}] takes f and threads it across the arguments which are fed to it in list form, so it gives {f[a],f[b],f[c]}, just like map works on lists with Map[f,{a,b,c}] yielding {f[a],f[b],f[c]}.
    • Thread doesn't just work on singular lists, though: Thread[f[{a,b,c},x]] will take that single x and duplicate it across the elements of the list in order to maintain a consistent final dimensionality, yielding {f[a,x],f[b,x],f[c,x]}. Note that if you think about the arguments of f being combined into a list of lists, {{a,x},{b,x},{c,x}}, Thread is stripping that internal list structure and giving the equivalent result to f@@@{{a,x},{b,x},{c,x}}.
    • Provided two (or more) lists, Thread will provide the respective elements of each list as a sequence (that is, a sequence of elements with no list structure, like the arguments to a function) to the threaded function, as is done above with the singleton x. So: Thread[f[{a,b,c},{1,2,3}]]=={f[a,1],f[b,2],f[c,3]}.
    • You can also mix and match these: try providing the reverse of what you see in the second subpoint here, or e.g. Thread[f[a,{x,y,z},b]] or even Thread[f[a,{x,y,z},b,{1,2,3}]].
    • Thread also can work over heads other than List, as long as you provide the head you'd like to thread over: Thread[f[a+b]] vs. Thread[f[a+b],Plus] should exemplify this. (Map automatically works over different heads with no specification—it's just that the most commonly used one is List.)
    • Thread can also function on only the first n arguments with Thread[f[arg1,arg2,arg3],h,n]. (This is not available for Map.)
    • Finally, Thread doesn't Hold its arguments and will evaluate in situations where you might not expect, which can cause some unpleasant surprises.
    • My estimation: Thread can let you do some very neat things very efficiently, but it's a little bit kitchen sink for my personal general use. Over time, you'll get a sense of where it might be the best function to use, and you'll then deploy it in those contexts.
  • Map is the "bread and butter" for taking a given function and operating it at a specific level.
    • Map[f,expr] takes a function f and "inserts" it at level 1 into expr. That's usually a list, but it doesn't need to be: Map[f,{a,b,c}]=={f[a],f[b],f[c]} and Map[f,a+b+c]==f[a]+f[b]+f[c] serve as examples.
    • More generally, Map doesn't care about the Head of expr, so we could say: Map[f,g[a,b,c]]==g[f[a],f[b],f[c]]. Hopefully you see how this general case reduces to the two specific ones prior.
    • With no level specified, Map works at level 1 only. We can specify a level with Map[f,expr,n].
      • If n is given just as an integer, Map will operate the function "down to" level n from level 1. This is easiest to see with a nested list; try this code to visualize it: Manipulate[TreeForm@Map[f, {{{3, 2}, {6, 7}}, {{9, 8}, {4, 1}}}, n], {n, 1, 3, 1}].
      • If n is given in braces (as {n}), then Map will operate the function only at that level. Analogously: Manipulate[TreeForm@Map[f, {{{3, 2}, {6, 7}}, {{9, 8}, {4, 1}}}, {n}], {n, 1, 3, 1}].
      • n can be negative, though in the case of non-rectangular expressions this can produce irregular results, as we discussed previously.
    • Map has many related functions which can be incredibly valuable when you need just slightly different functionality. Cf. MapAt, MapIndexed, KeyMap, KeyValueMap, and things like the newer SubsetMap.
    • Map should generally be your go-to function for "repeated function application". It's comparatively easy to understand and specify precisely what you want.
  • MapThread, as the name suggests, is a bit between these two functions—I might say that it acts like a simplified Thread that has many of the good qualities that you get by working with Map.
    • MapThread makes you explicitly specify the function and its arguments separately, leaving less to "interpretation".
      • MapThread[f,{{a,b,c},{x,y,z}}] gives you {f[a,x],f[b,y],f[c,z]}, and that kind of explains the primary idea.
    • Like Thread, you can provide as many lists as you like as arguments to be inserted into f: MapThread[f,{list1,list2,...}] works like Thread[f[list1,list2,...]] but in a more "transparent" way. (Plus, it holds evaluation until f is fed the sequence list1[[1]],list2[[1]],..., which is nice.)
      • Unlike Thread, you cannot specify a head other than List over which to thread f.
      • Unlike Map, MapThread only works on lists (and associations, which I'll explain shortly).
    • Like Map, you can specify a level like: MapThread[f,{list1,list2,...},n]. MapThread just takes the integer without a list format, as "down to" in the context of MapThread doesn't usually contextually make much sense.
    • MapThread is also coded to work with associations, so MapThread[f, {<|a -> 1, b -> 3|>, <|a -> 2, b -> 4|>}]==<|a -> f[1, 2], b -> f[3, 4]|>.
    • MapThread is the function of choice for when you have "parallel" lists of data and you want to combine them in some way where all their first elements are taken as a group, all their second elements are taken as a group, and so on. It's less confusing—but correspondingly less capable—version of Thread with some of the syntactic capabilities of Map in terms of how and where you can use it.

This is a lot of information, but hopefully it provides you with the overview you were looking for :).

POSTED BY: Arben Kalziqi

Hi Arben,

Interesting indeed, thanks for clarifying! In light of this, is there a solution to my original question? That is, how do I find out which functions accept (nested) lists as arguments and then work on each list element (at the innermost level)? E.g., for a 2x2 matrix I would like f[{{a,b},{c,d}}] = {{f[a],f[b]},{f[c],f[d]}}.

As mentioned, Rationalize is one example, but I can't see anything in its documentation stating that it works like this.

Cheers, Jörn

POSTED BY: Jörn Kersten

I suspect that there's not a way to query functions for that property, unfortunately. If you have a function f that you'd like to use at that level, you can always just do Map[f,mat,{2}] (or Map[f,mat,{-1}] for more deeply nested lists), or even write a new definition of f which takes care of that for you, like: f2[mat_List]:=Map[f,mat,{-1}].

Some more discussion has occurred in our internal chat, and I've learned some very surprising things about it—it seems to go all the way into any expression and rationalize any numbers found within. Try Rationalize[f[2.34]] and—if you're like me—become horrified.

Finally, let me quote one of our developers, who had a succinct and insightful comment:

I also want to point out that the Listable attribute is just an implementation detail. Having the attribute means a function will thread over lists, but the converse is not necessarily true, since that behavior can be achieved in multiple ways.

Compare these two functions for example: f // Attributes = { Listable }; f[ x_Integer ] := x + 1; g[ x_Integer ] := x + 1; g[ x_List ] := g /@ x Just because g appears to be listable doesn't mean it has (or even should have) the Listable attribute.

POSTED BY: Arben Kalziqi
Posted 2 years ago

How does one take the quiz? I have reviewed the material and I am ready to take quizzes 1 and 2.

POSTED BY: Matthew Rich
Posted 2 years ago

The links to Quiz 1 and Quiz 2 are included in every e-mail you get from the Wolfram U team. You should probably have gotten an e-mail "Recording available: Using Notebooks Effectively" at 5:52 PM Eastern Standard Time today. I'm another student; I don't want to send you my links because the the URLs in the e-mails have tags that identify the individual user. Good luck.

POSTED BY: Phil Earnhardt

Precisely, phil—thanks!

POSTED BY: Arben Kalziqi

Hi! Playing around with commands in the "Edit" menu, I've noticed an unexpected behaviour.

  1. Select some expression.
  2. Un/Comment Selection
  3. Un/Iconize Selection
  4. Un/Iconize Selection

I'd expect step 4 to simply undo step 3. Instead, the result is the expression "Null". Is this a bug? Cheers, Jörn

POSTED BY: Jörn Kersten

Hi Jörn—great observation. I do believe that you've found a bug; I'm inquiring about it and will generate a bug report if I'm correct. (Fortunately, in practice comments are not something that tend to get iconized, so hopefully this doesn't affect your workflow! It also might help to explain why nobody caught it, if it is indeed a bug.)

POSTED BY: Arben Kalziqi

Hi;

I am trying to use the Sin[] and Manipulate [] function to make a mathematical representation of a transverse wave - see attached. In simulation, I can get some of the sliders, but not all of them to work as expected. Possibly there is something that I am not understanding, but I don't understand what.

Thanks,

Mitch Sandlin

Attachments:
POSTED BY: Mitchell Sandlin

Hi Mitch—this is a mathematical thing, not a Mathematica-l thing, but: because you're using Plot as a function of time, any other terms (in the mathematical sense, "things which are added or subtracted together") in the argument of the sine can only serve as phase shifts. That is, 2 Pi f determines your frequency and 2 Pi / λ x - b will determine your phase. (This also explains the second part of your notebook.)

In order to see what's going on here a bit more clearly, I recommend plotting in both x and t:

Manipulate[
 Plot3D[Sin[(2 \[Pi])/\[Lambda] x - 2 \[Pi] f t - b], {t, 0, 2}, {x, 
   0, 2},
  PlotRange -> All,
  AxesLabel -> {"t", "x", "z"},
  PlotPoints -> 80],
 {f, 1, 2}, {\[Lambda], 1, 2}, {b, 0, 10}]

Consider that looking at any one t gives you a slice of this plot, and looking at any one x gives you an orthogonal slice of this plot. It can be confusing to try and visualize (and as somebody with aphantasia I'm hopeless at it myself), so I think it's important to be very careful about the language we use when we talk about a wave "traveling", for example. It's very easy to get things muddled, so I always keep the model I referred to above in mind. Namely:

  • If we're generating a 2D plot of a sine wave, it can always be parameterized as a Sin[k x - b]. a determines the amplitude, k determines the frequency (or wavelength), and b determines the phase—that's it; there's nothing more that can be said about it.

    • It doesn't matter that it's x there; that's just a dummy variable. In fact, the language we discussed in this study group might be helpful: really, it's a Sin[k # - b]&. You pick whatever variable you want to throw into that slot, but once it's in a plot and we've plugged numbers into it to get a series of points, it doesn't matter what we picked anymore.
  • If you do have two variables that you want to plot against—say, x and t—you need to use a different type of visualization in one sense or another. Plot3D lets you do that directly, since we can see and understand three-dimensional graphics objects. DensityPlot is another way to do it pretty directly.

    • The other option is to visualize 2D slices of that 3D visualization—this is what you did with the Manipulate, actually! We can visualize this, in a way—see attached notebook.

Hopefully this doesn't come off as side-stepping the question; let me know if this answer (and particularly the notebook) help to clear things up.

Attachments:
POSTED BY: Arben Kalziqi

Thanks so much.

Mitch Sandlin

POSTED BY: Mitchell Sandlin
Posted 2 years ago

I have a family member who works at a group doing cancer research at a local university. She would like to systematically (i.e., accurately and thoroughly) extract data from already-published science papers publishing statistical data on clinical trials and papers publishing epidemiological data on certain populations and sub-populations. Management has suggested she "just use machine learning" to make this a slam-dunk. Perhaps Wolfram Language has tools to help build this...

Can you point to any presentations where researchers have had success implementing this kind of science-paper-data-extraction application? Have systems been shown at past Wolfram Technology Conferences? Any published paper about the extraction proper? Given the massive variety of presentations for data in medical papers, this seems like a daunting problem.

POSTED BY: Phil Earnhardt

Hi phil—my initial suspicion is that yes, that's a very daunting problem and "just use machine learning" is coming from a place of understanding machine learning as a magic/silver bullet. I think in practice it might be possible to figure out where tables are and extract them from papers, but as you say: they could be presented in literally ~any way, so I don't know how it would be possible to actually extract data from them.

I'm wondering if there's something structural in PDFs—as long as they're proper PDFs, and not rasterized monstrosities—which would let you extract them in a more deterministic manner with our PDF import functionality. I'll try and look into this later today.

POSTED BY: Arben Kalziqi

phil, I did try to look into this, but I didn't have much luck. Perhaps PDFs can be formatted in a way that makes it easier to extract tables, but the variability there is its own issue. I do think that somebody could manage this with some amount of work, but I think it's beyond me for the time being. Sorry!

POSTED BY: Arben Kalziqi
Posted 2 years ago

Thank you so much. You went beyond the call of duty on this question.

Interestingly, I did locate science papers on automating the gathering of data (and separate papers on gathering metadata) from published science papers. I'm concentrating on this SG now; I haven't pursued any of those papers yet.

POSTED BY: Phil Earnhardt

Let me know if you find anything useful or interesting once you get around to reading those papers!

POSTED BY: Arben Kalziqi

I might expand on this later, but primarily I just don't think it's reasonably possible to implicitly know. You can chain and combine pure functions in any number of ways, and because the "variable(s)" for all of them are all just # (or #n), it's important to be able to explicitly delineate where one operation ends and another begins.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Why is an "&" necessary to mark the end of a pure function definition? Can't the front end implicitly know that the definition of the pure function is complete? What's an example where the front end requires the "&" delimiter -- some delimiter -- in order to parse the pure function correctly?

The choices made by Stephen, Theo, and all the others seem rational and well-designed, but I haven't sorted this one out yet.

POSTED BY: Phil Earnhardt

Hi everybody! As it turns out, the "Working with Data" example that I thought was broken in today's review actually does work—it's just that due to the somewhat strange nature of the import/generation of the data, the kernel didn't change the color of the associated symbols. So: after clicking "Create Sample Data", you'll be able to use numericData and housePriceDataRaw without issue despite their being blue. Once you start interacting with them, they should change to black :).

POSTED BY: Arben Kalziqi

I just completed Quiz 2 but when I press the "Get Results" button, nothing happens.

POSTED BY: Mitchell Sandlin

Hi Mitch—how frustrating! It works great for us on our end (and even returns the results a little faster than we're used to seeing, perhaps...). Have you tried another browser? If not, you might try clearing wolfram-related cookies from your browser data, annoyingly.

Specifically, try clearing the wolframcloud.com cookies. Finally, if that doesn't work, try deleting the quiz notebook that you'll find listed here.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Did you download as a notebook on your local machine? I noticed some strange behavior: I had Quiz 1 open for several hours and it cleared out all of its answers spontaneously. Quizzes are deployed from the cloud; perhaps you lost your connection to the server. I'd just reload the webpage, answer the questions again, and promptly [re-]submit it. That's pretty easy to do with quizzes like this.

POSTED BY: Phil Earnhardt
Posted 2 years ago

Where can I get elements.xls file?

POSTED BY: Updating Name

Added it to the Sample Data folder.

POSTED BY: Arben Kalziqi

Hi everybody—I've uploaded a filled-in Q&A transcript to the Course Materials folder (in the QnA subfolder). Here, I've gone through and added some notes/expanded upon some of the given answers—as well as filled in the very small number of questions which had not yet already been answered—for days 1-7 of this study group

This is a great way to review the material and prepare for quizzes, and also just has some generally "good to know" information, in my estimation. Please do check it out!

POSTED BY: Arben Kalziqi

will do. thanks.

POSTED BY: Jonathan Ansell

Regarding Quiz 1, is the answer to Question 9 correct? If so, could you kindly explain why at the appropriate time? thanks.

POSTED BY: Jonathan Ansell

Hi Jonathan—it is correct on my end, yes. We did have a key issue with an earlier version, but you shouldn't be experiencing that. I can't discuss quiz answers here, but please see the documentation for Apply. If that doesn't clear things up (which I expect it doesn't, or you probably wouldn't be asking), feel free to email me at my first name, last initial @wolfram.com and we can discuss specifics.

POSTED BY: Arben Kalziqi

Yesterday's notebook claimed in the section "High-precision Numbers" that numbers outside of the range [ $MinMachineNumber , $MaxMachineNumber] "are automatically represented using the system that is used for high-precision numbers". What does this mean? Are "high-precision numbers" the same as numbers in "arbitrary-precision arithmetic"? More importantly, how does this help me? N[Exp[100000000000000000]] still yields Overflow[].

POSTED BY: Jörn Kersten

Yesterday's notebook claimed in the section "High-precision Numbers" that numbers outside of the range [ MinMachineNumber,MaxMachineNumber] "are automatically represented using the system that is used for high-precision numbers". What does this mean? Are "high-precision numbers" the same as numbers in "arbitrary-precision arithmetic"?

Hi Jörn—I think that this documentation page will be informative for you. In short: my understanding of what we mean by "high precision" numbers is "any number with a precision higher than $MachinePrecision. These could come from approximations of infinite precision numbers (like rationals, integers, symbolic numbers, results of special functions, and so on), or they could just be manually entered or calculated numbers with precision higher than $MachinePrecision. When we say that they're "automatically represented", we mean that if you perform some operation with the appropriate precision throughout, we won't require you to manually change anything in order for your result to maintain that precision—e.g. you won't have to "type" the variable you save these results too as a special, higher-precision type variable.

More importantly, how does this help me? N[Exp[100000000000000000]] still yields Overflow[].

It helps you because you might want to do calculations which either return an infinite precision result or use numbers beyond $MaxMachineNumber in intermediate steps. That you get an overflow when trying to get that number per se is unavoidable, but you can still have and represent the expression Exp[100000000000000000], and use it in calculations. A clear example is:

N[Exp[100000000000000000]/Exp[100000000000000000 - 10000]]

If numbers greater than $MaxMachineNumber were not representable, then this computation would not be possible. Moreover, this:

N[Exp[100000000000000000]/Exp[100000000000000000 - 10000],10000]

would not be possible either.

POSTED BY: Arben Kalziqi

Hi Arben,

Thanks a lot for the explanations! Let me explain where my confusion arose, as it could be useful feedback for future courses.

First, "High-precision Numbers" is simply the wrong technical term. Numbers with a precision higher than $MachinePrecision are called "arbitrary-precision numbers" according to earlier parts of the notebook and the documentation page you've linked. This is a bit nitpicky, but it honestly confused me.

Second, I asked the wrong question. I should have asked "Why does N[Exp[100000000000000000]] yield Overflow if numbers larger than MaxMachineNumber are represented by arbitrary-precision numbers"? To which you would have answered that even for these numbers there's an upper limit, $MaxNumber.

For this reason I think it would be helpful to change the notebook slightly: just delete two zeros, and you arrive at a number that is still pretty big but can be handled by Mathematica.

In[55]:= N[Exp[1 000 000 000 000 000]]
Out[55]= 7.*10^434294481903251

Of course, there's no denying that it is impressive that Mathematica is able to do the calculations you've shown even with the larger number.

Cheers, Jörn

P.S. New question: how do I enter a dollar sign here without screwing up the output?

POSTED BY: Jörn Kersten
Posted 2 years ago

where can I find data2D.dat?

POSTED BY: Updating Name
Posted 2 years ago

If you go into the download directory https://amoeba.wolfram.com/index.php/s/TsKDGQ6MdpNxfwc , you'll see a sub-directory "Sample Data". You'll see a data2D.dat in there. The full URL of the file is https://amoeba.wolfram.com/index.php/s/TsKDGQ6MdpNxfwc/download?path=%2FSample%20Data&files=data2D.dat

POSTED BY: Phil Earnhardt

Thanks phil!

POSTED BY: Arben Kalziqi

A cheat sheet of the sometimes mysterious-looking abbreviations would be helpful. I think so far we have seen the following:
@
/@
@@
/.
/;
//
~
Did I miss any?

POSTED BY: Richard Laugesen

A few, but I wouldn't sweat it :) Those are the ones I use frequently (in addition to @@@), but I provided a few links showing ~all of the shortcuts in last week's review notebook. Those resources were:

POSTED BY: Arben Kalziqi

Thank you, very helpful links.

POSTED BY: Richard Laugesen
Posted 2 years ago

I saw that Richard had asked in today's Q&A about units—we have full support for physical units through the Quantity function. Units will correctly interact with each other and display in a nice way.

POSTED BY: Updating Name

When would one choose to use FindRoot rather than NSolve? At first glance, NSolve seems better since it promises to seek all roots. But, in what sort of situations is NSolve likely to fail and FindRoot succeed?

POSTED BY: Richard Laugesen

Hi Richard—good question. NSolve works mostly like Solve in that it's primarily built for solving polynomial equations and will usually run into trouble for more general equations that can involve transcendental functions. FindRoot is much more general, but the tradeoff is that it needs a starting point and can only return one root at a time because it works iteratively until it finds a solution.

Reduce is (very very hand-wavily) a bit in between these two, and should stay on your radar as a potential solver (as long as you offer sufficient restrictions, e.g. reducing over the reals).

POSTED BY: Arben Kalziqi

How would I don this using Map? Thank you. Visualize {1,4,3,5,2} with a piechart,numberline,lineplot and barchart.Place these in a 2×2 grid.

POSTED BY: Jonathan Ansell
Posted 2 years ago

Hi Jonathan,

A couple of ways to do this

data = {1, 4, 3, 5, 2};
plotFunctions = {PieChart, NumberLinePlot, ListPlot, BarChart};

Using Through

Through[plotFunctions[data]] // Partition[#, UpTo@2] & //
 Grid[#,
   Frame -> All,
   Spacings -> {1, 1}] &

enter image description here

Using MapThread is more flexible

options = {
  {ColorFunction -> "Pastel"}, 
  {PlotStyle -> Blue},
  {PlotTheme -> "Scientific"}, 
  {ChartLabels -> Alphabet[][[;; Length@data]], ChartStyle -> "DarkRainbow"}}

MapThread[#[data, #2, PlotLabel -> #] &, {plotFunctions, options}] // 
 Partition[#, UpTo@2] & //
 Grid[#,
   Frame -> All,
   Spacings -> {1, 1}] &

enter image description here

POSTED BY: Rohit Namjoshi
Posted 2 years ago

Thank you, Rohit. I'd never seen the details about serving up multiple representations of data simultaneously.

POSTED BY: Phil Earnhardt

Great answer—thank you Rohit!

POSTED BY: Arben Kalziqi

Hi; Below please find a notebook outlining a problem that I have been working on for some time. It involves importing data from a Microsoft OneNote file into a Wolfram notebook. Basically, I can figure out how to open the OneNote file but cannot figure out how to select the exact document from the OneNote file. Please review my attachments.

Thanks,

Mitch Sandlin

Attachment

POSTED BY: Mitchell Sandlin
Posted 2 years ago

You could try this.

POSTED BY: Rohit Namjoshi

Hi Rohit;

I followed the information that you supplied the best that I could, still couldn't acquire the desired results. However, I do believe that we are closer. See Attached

Thanks,

Mitch Sandlin

Attachments:
POSTED BY: Mitchell Sandlin

Hi Mitch—please do provide the OneNote file! In your notebooks, we don't have access to your computer so we can't get the file. (Unless there's confidential information or something in there, in which case a sample file would be useful)

POSTED BY: Arben Kalziqi

Hi Arben;

When I try to attach the OneNote file for Windows 10 (.one suffix I believe), I receive a message that the file type is not supported and the "Add a file ..." operation is terminated. Can I send the file to an email, or is there a workaround to the message?

Thanks,

Mitch Sandlin

POSTED BY: Mitchell Sandlin

Feel free to email it to me—it's first name, last initial @wolfram.com.

POSTED BY: Arben Kalziqi

Hi Mitch—I think I'd need the actual OneNote file to try anything here, as I don't use many Office products and don't have any experience with this.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Please see the background information in the attached "Impedance Background" Notebook (including a link to the RMT Ropes "dragon roll" video). Questions: 1. How can I make a simple animation that approximates the path of the centerline of the RMT rope motion? Is there an example of this helical path somewhere? 2. I'd like to compute a path based on the approximate forces on the rope, and show the resistance/reactance forces in a separate panel. I'd like to show the phase relationship between resistance/reactance, but not freak out people unfamiliar with the complex number representation of impedance. Suggestions? 3. Does Mathematica provide a way to visually capture the 3D path of [a marked] centerline of the rope? I may need to stitch the inputs from multiple cameras together? I was thinking of producing a 3DP of this captured path.

One unrelated request: can you capture an audio sample from your cat and show us a Fourier transform of it for the study group? Do we look at Fourier transforms? Maybe your cat just wants to contribute to the presentation. Meeeeeow.

POSTED BY: Phil Earnhardt
  1. How can I make a simple animation that approximates the path of the centerline of the RMT rope motion? Is there an example of this helical path somewhere?

Unfortunately, I can't say I'm familiar with this type of motion and don't know how to parameterize it—if you make your own thread here on Wolfram Community, I don't doubt that somebody might be able to figure it out. It kinda looks like a lemniscate that oscillates ~sinusoidally in height? See my attached notebook for some thoughts.

  1. I'd like to compute a path based on the approximate forces on the rope, and show the resistance/reactance forces in a separate panel. I'd like to show the phase relationship between resistance/reactance, but not freak out people unfamiliar with the complex number representation of impedance. Suggestions?

Rather than using complex numbers, you could always explicitly break it down into real and imaginary components and only talk about them in real terms. In some cases there's no avoiding it, but you should be good to "brush away" most of the "complexity" here, right?

  1. Does Mathematica provide a way to visually capture the 3D path of [a marked] centerline of the rope? I may need to stitch the inputs from multiple cameras together? I was thinking of producing a 3DP of this captured path.

If the video were 3D (or a sequence of 3D images), sure—but otherwise, there's not a good way to do this from a 2D video. I suppose if you had a marking which was sufficiently large, a high enough framerate, and good camera placement, you could do it with one video. With two cameras, yes—you could measure (say) x-y motion in one video and z in the other, then put those tracked positions together. Consider a function like ImageKeypoints; you may have to do a little putzing with it but extracting this sort of data from a well-composed video (or videos) is possible, and I've done it.

Of note, you can also use Wolfram Language's Dynamic functionality to read in instrument outputs in real-time, so if you had some other way to measure, that could also work.

One unrelated request: can you capture an audio sample from your cat and show us a Fourier transform of it for the study group? Do we look at Fourier transforms? Maybe your cat just wants to contribute to the presentation. Meeeeeow.

We may briefly discuss them later in the sessions, as I do have an Images, Audio, and Video notebook that I wrote—I'll add an official Meechy Meow.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Tremendous commentary Arben! I'd been wondering why we needed a PhD to be leading this course; I'm wondering no more. I'll almost certainly defer diving into this for the next two weeks, but will definitely pick it back up.

After our work with Point[] yesterday, it would certainly be educational to have an animated point moving around the path (and indicating the changes in velocity). This would be similar to graphically showing the orbits of planets in the solar system on their respective ellipses with a higher velocity as they get closer to the sun located at one foci. That would probably be a better problem to look at first. Do I just need Animate[] to be moving that point along a curve?

Two comments about the RMT Ropes "dragon roll": I'm fairly certain that our bones, muscles, and CNS never ever encountered any movement like this before. While awkward at first, our CNS does figure it out, and then it figures out how to polish the movement to be graceful and efficient. We don't have to know a peep about the physics or its computation; we just do it. When I was moving with the rope this AM, I noticed that it's certainly possible to move through the pattern without touching the ground (i.e., getting any lifting force from that bounce). However, the required forces to get the rope over your head are far smaller if you let the bounce happen. That's the general theme of impedance and gait in the human body: reactance doesn't usually make the movement possible; it makes the movement significantly more efficient. Again, it's astonishing that the CNS just notices that bounce, rolls with it, and figures out how to #!$$ use it. The CNS-controlled biomechanics of the human body are dazzling and humbling.

POSTED BY: Phil Earnhardt

Ha! I'm not sure it's necessary—we have people from so many backgrounds who teach Wolfram Language super well—but it helps with the broader types of questions we can get, for sure.

After our work with Point[] yesterday, it would certainly be educational to have an animated point moving around the path (and indicating the changes in velocity). This would be similar to graphically showing the orbits of planets in the solar system on their respective ellipses with a higher velocity as they get closer to the sun located at one foci. That would probably be a better problem to look at first. Do I just need Animate[] to be moving that point along a curve?

Yes, just Manipulate or Animate will suffice if you have a functional representation of the position of the body over time. For an elliptical orbit, it can get a little complicated—but I think with some assumptions you should be able to write something down. However, if you wanted to be a bit cutesy about it, you could use our NBodySimulation function... let's try it with three bodies, using the entity framework's knowledge about the masses of celestial bodies. This example is lightly modified from the documentation:

Maybe try to modify this to look at just two bodies of your choosing!

Perhaps more to the point of your question... consider this:

Two comments about the RMT Ropes "dragon roll": I'm fairly certain that our bones, muscles, and CNS never ever encountered any movement like this before. While awkward at first, our CNS does figure it out, and then it figures out how to polish the movement to be graceful and efficient. We don't have to know a peep about the physics or its computation; we just do it. When I was moving with the rope this AM, I noticed that it's certainly possible to move through the pattern without touching the ground (i.e., getting any lifting force from that bounce). However, the required forces to get the rope over your head are far smaller if you let the bounce happen. That's the general theme of impedance and gait in the human body: reactance doesn't usually make the movement possible; it makes the movement significantly more efficient. Again, it's astonishing that the CNS just notices that bounce, rolls with it, and figures out how to #!$$ use it. The CNS-controlled biomechanics of the human body are dazzling and humbling.

It is indeed pretty incredible—I've done a lot of powerlifting in my life and trained up many new people, and in all cases it's amazing to watch how people adapt in a way that clearly isn't just due to increased strength, but increased proprioception.

POSTED BY: Arben Kalziqi

Thanks, now you've taught us SolveValues, which makes it easy to extract the desired solutions.

POSTED BY: Richard Laugesen

Glad it's useful! For completeness, you could cleverly turn a rule into a definition, in any case, with: Set@@(x->a) which is equivalent to: Apply[Set,x->a]

POSTED BY: Arben Kalziqi

Thanks, nice to see how Set works in this context to create an assignment.

POSTED BY: Richard Laugesen

Could you remind us how to let x equal (say) the first solution of Solve[x^2 + a x + b == 0, x] ? The Solve command outputs replacement rules, and my question is about how to turn that rule into an assignment to the variable x.

POSTED BY: Richard Laugesen

Hi again!

Looking at the "Cleaning Up Data" example of day 2, I wanted to generalize the replacement to work on anything that is not a number, not just the specified strings "N/A" etc. So I'd have to replace the parts of a list that yield False when the test function NumberQ is applied. However, something like col /. _?Not[NumberQ] -> 42 doesn't do the trick (where col is a list of numbers and other objects like in the example).

Defining a new test function notNumberQ[x_] := Not[NumberQ[x]] and then using this function in the replacement does work but seems a bit clunky.

Is there a more elegant way to realize replacements with combined test functions?

Ciao, Jörn

POSTED BY: Jörn Kersten

Hi Jörn, yes—try Conditional aka /;.

col/.s_/;!NumericQ[s]->42

should do it.

POSTED BY: Arben Kalziqi

Hi Arben!

Afraid not, this replaces the whole list by 42:

Cheers, Jörn

POSTED BY: Jörn Kersten

Ah, of course—the list itself is not a number... in that case, we should explicitly specify a level rather than replacing all of the expressions which match: Replace[col,s_/;!NumericQ@s->42,1]

POSTED BY: Arben Kalziqi

Got it, thanks! Jörn

POSTED BY: Jörn Kersten

Hi!

Hoping this hasn't been asked already: we've seen on day 2 that Map[f, g[a,b,c]] yields g[f[a],f[b],f[c]]. This no longer works if g is a function:

I get the logic: g[x,y] is replaced by Plus[1, Times[x,y]], and only then the mapping happens. But what would I have to do to get the expected result, g[f[x],f[y]] = f[x] f[y] + 1?

Cheers, Jörn

POSTED BY: Jörn Kersten

There are a few ways to do this; perhaps the best (and this is a rare suggestion from me...) is UpValues. For your case, that would look like: g /: g[f[x_], f[y_]] := f[x] f[y] + 1 That actually associates a definition to g, which—while the neatest way to do this, according to my intuition about what you might want—is perhaps a bit much. You can cleverly do this while sticking to Map just with a little level specification:

In[226]:= g[x_, y_] := x y + 1

In[227]:= Map[f, g[x, y], {2}]

Out[227]= 1 + f[x] f[y]
POSTED BY: Arben Kalziqi

Hi Arben;

Many, many moons ago, you helped me with a column plot, which I have been refining ever since. There are two final refinements than I have been working on but have not been able to figure out as of yet and was wondering if you could help me - see attached.

  1. Move the Ticks of the 3rd plot all the way to the bottom. Currently, they seem congested at the origin position. I have not found anything in the documentation that allows me to move the Ticks.

  2. I would like to implement your earlier suggestion and key the colors of the Ticks to the legend (say red, Blue and black). Changing the legend is not a problem, but changing the Ticks are. I have unsuccessfully tried several things which did not work and thought I would ask.

Thanks,

Mitch Sandlin

POSTED BY: Mitchell Sandlin

Hi Mitch—yes, I remember this. Attached is my best shot, if I've read what you've said here correctly.

  1. For the last plot, I've changed from the default (axis) display to a frame display, choosing to only display the frame on the bottom and left edges (the left frame edge replaces the y axis). I've used this to place not Ticks, but FrameTicks at the very bottom. I set the frame opacity to 0, and then set the frame ticks opacity to 1. This is necessary because without manual specification of the frame ticks style, they inherit the style of their associated frame. I updated the previous two plots to only have left frames; they keep their axes, removed the gridline at x=0, and slightly modified their plot range paddings so that the frames appear more like axes.

  2. To put it technically, this can often be a bit of a PITA. In this case, however, because of the way that Epilog works, you can just outright write the color inside the list of graphics options which specifies epilog. I've done that and changed the point sizes to all be equivalent, assuming that you want only the color to be the distinguishing factor. (Easy enough to change back if not, of course.)

Here's what I get for a final result:

enter image description here

I don't love that the points on the edges are cut off... it's due to the PlotRangePadding option. You can change that from {0,.1} to just .1 and it'll fix it, but it adds a liiiiittle space between the plot itself and the frame-edge that's serving as our y axis. If you do that, you probably want to modify the ticks such that the 0 is not included, because it looks cluttered... not sure how to avoid this presently, so pick your poison!

Attachments:
POSTED BY: Arben Kalziqi

Perfect, thanks so much.

Mitch Sandlin

POSTED BY: Mitchell Sandlin

I am writing custom Packages. I have two questions:

(1) What is the required or preferred filetype for a user-defined package: ".m", ".wl", ".nb", or ".wls"? (2) How do I specify the directory that the package resides in?

Attached, I've provided an example of my first attempt at Package Development. It appears to perform as expected.

I'm needing help on file administrative details.

Regards, Edward

Attachments:
POSTED BY: Edward Newsome

Drawing Tools palette: where can I find it in Mathematica 13.2 on a Mac? I do not see it in the Graphics menu or the Palettes menu.

POSTED BY: Richard Laugesen

In a rather rare occurrence, I believe that this functionality has been subsumed into the new "canvas" functionality, accessible through Graphics -> New Canvas. If this is missing some functionality that you need, please let me know and I'll inquire with our team about it, as I've never used this functionality myself.

POSTED BY: Arben Kalziqi
Posted 2 years ago

That's a wonderful initiative to spread Wolfram to new learners. Thanks @Arben.

POSTED BY: Farial Mahmod

You're very welcome!

POSTED BY: Arben Kalziqi

A few questions from a beginner:

  1. All Functions: the basic syntax of functions, how to interpret and resolve error messages, how to use help pages, how to find the best function(s) to use in a given situation
  2. Shortcuts/Cheatsheets: Keyboard, shortcut keys, and other cheatsheets pages to help navigate the syntax, system, etc.
  3. Best practices/tips and tricks: writing code, debugging, making it intelligible to others, most useful general functions, etc.
  4. Entities/Datasets: list of available items, how to best pull data, identify data elements available within in, the best way to utilize, etc.
  5. Specific functions: MAP and related functions - step x step and primary ways it's used. How to find the longest word in WordList[] Thanks.
POSTED BY: Jonathan Ansell
Posted 2 years ago

How to find the longest word in WordList[]

WordList[] // MaximalBy[StringLength]
(* {"electroencephalography"} *)
POSTED BY: Rohit Namjoshi

Hi Jonathan—point by point:

Functions

  • All functions take the form FuncName[arg1,arg2,...] (they could also have zero arguments). The arguments could really be anything at all, from integers to strings to lists to images to videos to neural nets.
  • When you get an error message, read it carefully—it's usually pretty instructive. You might see a red little set of ellipses by the cell bracket; click that to get more info.
  • Finding the best functions is like finding the best words when constructing a sentence: you can only get there by practicing and by reading. In this case, I recommend just trying things out—if they don't work, or you think they could be better, go to the documentation and read about the basic examples, the scope, and the neat examples. Most importantly, check out the Related Functions at the bottom, because this is where you'll often find a function that does the job better if what you're currently using doesn't seem quite right.

Shortcuts

I think that the links in today's review notebook (available in the course materials folder) should help you out here.

Best Practices

We'll talk about best practices, tips and tricks, and so on in the coming sessions. In the meantime, a few basic tips:

  • You have full access to text cells, so use 'em! You can explain what each chunk of your code does while keeping the notebook looking clean and stylish.
  • Be careful about writing ultra-cool compact code. It is indeed very neat, but it can be hard to decipher. Break things up and space them out to a degree you think is reasonable, so long as performance isn't too negatively affected. I don't do this for my own personal code and I can wind up with stuff like this: StringTake[ LongestCommonSubsequence @@ StringTakeDrop[#, StringLength@#/2], 1] & /@ StringSplit[d3dat, "\n"] /. Thread[#~Join~Capitalize@# &@Alphabet[] -> Range@52] // Total or this: Boole@*Or @@ SubsetQ @@@ {#, Reverse@#} & /@ (Range @@@ ToExpression@StringPart[{##}, {1, 3}] & @@@ StringSplit[ StringSplit[ dat, "\n"], ","]) // Total Don't be like me!

Entities

The best way to see if what you're looking for might exist in entity form is—for my money—just by pressing ctrl+= and typing it in natural language. Otherwise, it can be a bit tricky to navigate until you're familiar with the types of entities which exist (which you could see by evaluating EntityValue, if you like). Once you have an entity 'ent', you can ask for its properties by running ent["Properties"]. Some of the properties might not be available for your particular entity, but they'll still be listed here because they're available for other members of that type (e.g. think of some properties of elements [chemical elements, not programming elements!] which might exist for some elements but not others).

Map and Related Functions

(J., this will be relevant to you too, so hopefully you see it.)

  • Map simply takes some expression (generally a function) and "acts" it across a list at whatever level you desire (by default, at the top level). So: Map[f,{a,b,c}]=={f[a],f[b],f[c]}. It also has the shorthand /@, so you could rewrite that as f/@{a,b,c} and get the same result.

    • Mapping can be thought of as the primary way to avoid looping through lists (nested or not) when you have some operation that needs to be performed to the elements of a list.
  • MapApply, the recently-named full form of the diabolical-looking @@@, maps Apply, for some expression f, to the elements of a list. In other words: MapApply[f,{g[x],g[y],g[z]}]=={f[x],f[y],f[z]}. You could also do, say: List@@@{a+b+c,x*y*z,g[1,2,3]} to get {{a,b,c},{x,y,z},{1,2,3}}.

  • MapThread (no shorthand that I'm aware of) takes a functional needle and uses it to thread together corresponding elements of two or more lists. A basic example: MapThread[f,{{a,b,c},{1,2,3}}]=={f[a,1],f[b,2],f[c,3]}. You can use pure anonymous functions as its first argument, like: MapThread[#1^#2+#3&,{{a,b,c},{1,2,3},{4,5,6}}] to get {a^1+4,b^2+5,c^3+6}.

Hopefully this helps!

POSTED BY: Arben Kalziqi
Posted 2 years ago

Hello all, please see notebook.

enter image description here

Attachments:
POSTED BY: Paulo Moura
Posted 2 years ago

Use RuleDelayed

gr /. {p_Real, q_Real} :> {q, p}
POSTED BY: Rohit Namjoshi
Posted 2 years ago

I am having troubles importing the exercises into Wolfram Cloud application. I am working on android tablet and I extracted the exercises into Download folder. There is no import option. Please help.

Attachment

Attachments:
POSTED BY: Alex Kuznetsov

Hi Alex—frustratingly, as far as I can tell, the application doesn't have the option to import a notebook. However, if you go to https://wolframcloud.com in your web browser, you should be able to upload the notebook from there and then interact with it through the app.

POSTED BY: Arben Kalziqi

It’s the same situation in the iPad/iOS flavor of the app.enter image description here

I think I had to upload notebooks from the desktop version during my previous testing. :-(

The web interface has a button which will allow you to upload notebooks… enter image description here

POSTED BY: J. Leko

Arben,

Don’t know whether it’s germane to the discussion today, but can you explain the difference between Animate[], and Manipulate[]? To me, they appear to do the same thing.

Thanks.

POSTED BY: J. Leko

It's a totally relevant and reasonable question to ask. They are indeed very similar, and I don't believe Animate does anything that Manipulate can't: it's basically a stripped down version of the full Manipulate interface which has fewer possible options and which automatically begins animating upon evaluation, that's all!

POSTED BY: Arben Kalziqi

Hi everybody—I've added today's data files to the Course Materials folder, so you can now use them while trying out today's notebook yourself.

POSTED BY: Arben Kalziqi

In data visualization, I am trying to visualize the relationship as to how the surface area of a sphere and its volume changes as the radius increases using the two formulas below:

Surface area of a Sphere - 4 [Pi] r^2 Volume of a Sphere = 4/3 [Pi] r^3

I am using Manipulate[] function to increase the radius - see attached. However, visualization of the output is difficult since the output of the surface area is in square meters and the output of the volume is in cubic meters - two different units of measure. Please give me some direction as to what visualization function to use.

Thanks,

Mitchell Sandlin

Attachments:
POSTED BY: Mitchell Sandlin

Hi Mitch—you could calculate their ratio, or perhaps use the QuantityMagnitude function?

POSTED BY: Arben Kalziqi

Hello all, please see notebook.

enter image description here

Attachments:
POSTED BY: Peter Liedermann

Hi Peter! It's a fair point; I was mixing up my comparisons in a way that could well be confusing. Honestly, my intent was not to make a fair comparison between a properly-specified loop construct and mapping, but to—maybe a bit too theatrically—demonstrate that the former is messy and "redundant" compared to the latter.

(And re: list[i], I think the audio should indicate that the idea was "something like" or "some function of" or "something to do with", trying to indicate that inside the loop, we'd be doing something that required us to index list with a dummy variable, whereas with Map we wouldn't need to do that.)

Still, it could lead to confusion, so my apologies for that!

POSTED BY: Arben Kalziqi
Posted 2 years ago

Fortran and its children has been around since the late 1950s. i, j, and k -- even the rarely-used k -- have had a glorious 65 years in the sun. We should stop invoking their name (and their semantics) in the age of functional programming and fluid mappings. We should honor their heritage -- but only in museums and history books. [Feel free to steal this for future classes, Arben.]

POSTED BY: Updating Name

Hello, i, j, and k are still legitimate names wherever the user of a language has a choice at all. Fortran speciality was that names starting with i,j,k and as a matter of fact l,m, and n were associated with integers if not otherwise specified. Later descendants of FORTRAN avoided giving any pre-defined semantics to names; PL/I took an extreme attitude and despite being a colossal language had no reserved words at all, cf. https://www.ibm.com/docs/en/epfz/5.3?topic=sbcs-identifiers Therefore, in subprograms it was mandatory to supply declarations with attribute BUILTIN if desired to revert to the original definition of standard functions.

POSTED BY: Peter Liedermann
Posted 2 years ago

Hello, i, j, and k are still legitimate names wherever the user of a language has a choice at all.

You completely misunderstood. I wasn't talking about the semantics and interpretation of any programming language. I was talking about the meaning of those variables that has been burned into the brains of generations of programming students. I did think it was kinda neat that some version of [iteration variables] have been around for ~65 years -- the traditional age of retirement -- and perhaps it's time to give [iteration variables] a metaphorical retirement.

POSTED BY: Phil Earnhardt
Posted 2 years ago

I see tomorrow is about visualization. I have a data-visualization project: create beautiful animations of our "Anatomy Trains", and maybe an AT coloring book. About 20 years ago, Tom Myers authored "Anatomy Trains: Myofascial Meridians for Manual Therapists and Movement Professionals". It's a mapping of the major lines of tension in our structural network that give us structure, movement, and the ability to do work. Each line contains multiple muscles and tendons, with the lines passing through bones (but not at the ends of the bones). Myers describes them far more eloquently; anyone curious can see a brief description of each of the lines he wrote in this PDF file (jump to p. 12).

I would like to use Wolfram's anatomy libraries to display a subset of human bones, muscles, and tendons. I think showing 1 or 2 lines would provide the most clarity. I'd use a 3D visualization allowing the user to rotate, zoom, and pan through the images. This sounds relatively straightforward to create the Wolfram Language code and publish as a notebook and/or a CDF.

One radical idea came to mind: it would be neat to allow a fly-through of the 3D model along a curve. The viewer could stop the fly-through at any point, and zoom/pan/rotate the model from that particular perspective. This is beyond my capability in the language: I found myself wanting a built-in operation to do fly-throughs of a 3D model. Allowing students to directly manipulate the models would be best, but it would be nice to also create videos of the lines.

Is my first part all doable? Do the built-in 3D viewers do what I need, or should I be wrapping this around a Manipulate[]?

POSTED BY: Phil Earnhardt

Hi again Phil—the first part should be doable without issue with just the regular Graphics3D interface (e.g. what you see when you use Plot3D or anything like that). The second part is also doable, but in a few different ways... I think the best way would be to use Animate or Manipulate (along with some of the camera positioning/perspective options). This way, you could set up the visualization to animate however you like (w.r.t. the flythrough and all), and the user could pause it at any point to rotate it and so on because in the end, it's still a Graphics3D object like discussed above.

This could be a bit tricky to set up, as flythroughs are much easier to explain than they are to code, but it can absolutely be done. Exporting a video would also be completely trivial!

POSTED BY: Arben Kalziqi
Posted 2 years ago

From comments in the presentation today, I believe there is some other place that [many] questions are being asked/answered. I don't see that area or any way to get to it. What am I missing? Help!

POSTED BY: Phil Earnhardt
Posted 2 years ago

Aha. I found the Q&A button in the BigMarker software while replaying today's session. I'll look for that icon tomorrow during the live session. Are the questions of other participants viewable, or can I only view my own questions and answers? TY.

POSTED BY: Phil Earnhardt

Hey Phil—glad you found it, and hope you can make use of it for the rest of the sessions (And just to repeat: we collect all of these Q&As and upload them at the end of each week, as well as have a full session Q&A with questions submitted through the post-session survey.)

Questions and answers are, by default, not visible to other participants, but we can (and do) "publish" them so that they become visible. Not all questions will be published for everybody to see in real-time, but many will.

POSTED BY: Arben Kalziqi

Can you explain the difference between Block[], and Module[] when used for local variable scoping? To me, but Block[] example isn’t clear…

POSTED BY: J. Leko

Hi J—if it works for you, I'm happy to discuss that in some depth at Friday's review session so everybody can see it and hear it explained. (If you need an answer sooner, I could write it up here.)

POSTED BY: Arben Kalziqi

Friday is fine. Thanks!

POSTED BY: J. Leko

Arben,

One area I’ve struggled with concerns Levels of expressions. So in preparation for my question(s) concerning MapAt, and MapThread, I figured I’d study “the book” (https://reference.wolfram.com/language/tutorial/Expressions.html#24855). I do alright until almost the very end where negative Levels are introduced…

Level[u, {-1}] results in {a, a, a, a, f} because these are the bottom leaves on the TreeForm, as near as I understand it. Where things start going sideways is when Depth[] is introduced. The next example shows, Depth[g[a]] which returns 2. Why is it two? Is it because Depth counts the expression head, “g” as well as the argument “a” as a level?

enter image description here

The final example also doesn’t behave as I expect. It says, Level[u, {-2}] results in {g[a], h[a]}, but if we’re starting at the bottom of the TreeForm and proceeding up two levels, why aren’t {f[a], f[a], f[f]} also included? They all have two levels up from the bottom of the TreeForm…

enter image description here

POSTED BY: J. Leko

Hi J—some great questions here, and I'm glad that you're perusing the documentation and getting some evidently great use of it. Let's see if I can't help out with these questions, one by one:

Why is it two? Is it because Depth counts the expression head, “g” as well as the argument “a” as a level?

As I understand it, yes—that's exactly why. Since you've asked specifically for the depth required to write g[a] (rather than, say, a), you're getting the level at which g[a] could first appear, traversing a tree down from the top. The a inside the g[a] is indeed one level deeper (at level 3, in u), but any non-atomic expression will by necessity span multiple levels when asked for in this manner, right? I.e., any non-atomic expression can be represented as head[el,...], so if you ask for the Depth of such an expression, we return the depth corresponding to where that expression could begin, despite the fact that the el exists one level deeper (and el could itself be compound, so it could keep going down the tree).

The final example also doesn’t behave as I expect. It says, Level[u, {-2}] results in {g[a], h[a]}, but if we’re starting at the bottom of the TreeForm and proceeding up two levels, why aren’t {f[a], f[a], f[f]} also included? They all have two levels up from the bottom of the TreeForm…

I agree that this is a confusing, and I think it's partly our eyes playing tricks on us because of how TreeForm represents expressions; I would have guessed the exact same thing that you did. However, there's one clue in your image: what's special about the two branches which were actually returned? They're vertical. Why should that matter? It seems like it shouldn't, but...

Take a look at u once again. It's:

u=f[f[g[a], a], a, h[a], f]

Notice what's missing: do you see any f[a] or f[f]? They don't actually exist in u; they only exist if you're extracting certain branches within u. Level is just telling us which expressions within u which explicitly exist and have a level of precisely -2—and that's g[a] and h[a], and nothing else.

Hopefully that's a sufficiently satisfying response! I've asked our tech folks if this understanding is correct, and will update here when I hear back.

POSTED BY: Arben Kalziqi
Posted 2 years ago

Thanks for clarifying these issues, Arben!

POSTED BY: Updating Name

Of course! I've received confirmation that this is the right way to think of this, and suggested a way of looking at the expression that might make this clearer still: ExpressionTree[u, "Subexpressions"]

POSTED BY: Arben Kalziqi

Hi all; Let's work out the final example of the already quoted

https://reference.wolfram.com/language/tutorial/Expressions.html#24855)

Level[u, {-2}] We must determine "The parts of u at level -2 are those that have depth exactly 2:" We refer to the drawing as in the above documentation, assuming a directed graph whose edges point "downward" in the representation.

the Depth of the root is 4, corresponding to the 4 levels, arranged horizontally in the given representation (Of course, the concept of Depth is independent of the drawing) In the f-a-h-f-line, the depths are 3-1-2-1 respectively. In the g-a-a-line, the Depths are 2-1-1 respectively This yields the desired result.

Why aren't the technical writers of Wolfram able to give proper recursive definitions of this stuff? Cheers Peter

POSTED BY: Peter Liedermann

Hi Peter, please see the documentation for Depth, noting specifically that Depth takes one argument—expression depth in this sense is not context-dependent.

POSTED BY: Arben Kalziqi

Here is an attempt to recursively define Depth using Level with positive second parameter. this could in turn be used for a recursive definition for negative second parameter of Level and verified by the examples loc. cit.

POSTED BY: Peter Liedermann

Hi;

Yesterday I noticed that you used a picture of your cat as input to a Sin[] function. I was under the impression that all input to Sin[], Cos[], Tan[], ect. needed to be in radians and if the input was not in radians, then it had to be multiplied by 2 Pi to get it in radians.

Thanks,

Mitch Sandlin

POSTED BY: Mitchell Sandlin

Mitch,

Per the documentation for these functions, the arguments are assumed to be in radians. You can use the function Degree to convert between degrees and radians.

Hope this helps.

J.

POSTED BY: J. Leko

Indeed, they are assumed to be in radians—but Sin (and the other trig functions) have an Attribute called Listable. This means that when you feed them a list of any kind, they automatically go inside the list and work at the lowest possible level: try, for example, Sin[{1,2,3}] or Sin[RandomInteger[{0,9},{5,5}] and you'll see.

The magic ("") here occurs when when feeding an image to Sin: some functions, when fed an image, bypass the Image part of the expression and work directly on the ImageData, e.g. the matrix of RGB pixel values of an image. Because a matrix of RGB pixel values is simply a nested list (height, width, then 3 color values per pixel), Sin is happy to go in there and work on all of the pixel values.

So, Sin[img] gives Image[Sin[ImageData[img]]], or: Sin of an image returns a new image where the R, G, and B values of every pixel of the image have had their sine taken. (And because Sin expects radians, it treats those values like radians.)

Hopefully that clarifies things!

Attachments:
POSTED BY: Arben Kalziqi
Posted 2 years ago

Great content thus far....

I wanted to ask about wolfram being leveraged as part of a larger code base. How would that work?

POSTED BY: Matthew Rich
Posted 2 years ago

Arben, do you have a sampledata.xls file that we can download into our local computers? Alternatively, do you have the URL for a sampledata.xls? You may have identified teh URL in your presentation, but I didn't write it down. TY.

POSTED BY: Phil Earnhardt

Hey Phil! Good call—I've added that file to the Course Materials folder. The link should be in your reminder emails!

POSTED BY: Arben Kalziqi

Hi.

As someone with previous Mathematica experience (over 20 years ago!), I’m looking forward to this review. Since I work from an iPad, I’m interested in learning the differences between the desktop and on-line versions of the program. So far, the distinction between commands like CloudExport, and Export are lost on me. Hope we can (briefly) address these topics.

Look forward to getting started. Thanks.

J.

POSTED BY: J. Leko

Hi J! We'll talk a little bit about the difference between local and cloud functionalities for sure. Of course, if you want more information or clarification or would like to get into specifics more than we do in the lessons, you can submit your question for one of our weekly review sessions and I'll go over it in more detail :).

Looking forward to seeing you there!

POSTED BY: Arben Kalziqi
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract