Mathematica Manipulate & PopupMenu - dynamic

I'm new here and I've one question about the Manipulate function i Mathematica: I need to plot some data of a nested list where the first coordinate selects a category (of stocks, like banks, automobiles, pharmaceuticals, ...) and inside every category there are years and months coordinates, so it should be something like
In:= list[[cat]][[yr]][[mnth]]
Out= {1,2,3,4,5,6}
which are sorted stock prices belonging to category cat.
Now I'd like to plot this with an dynamic index in Manipulate with a PopupMenu which allows to select the category i need to plot: I already have a vector sect which at position cat has the sector referring to cat in list (which is to say sect[[i]] is the category of list[[i]]), but results are poor.
I've tried to use Manipulate[...,{index,sect}] and it seems to be the right way since there actually is a popup menu in the output, but it still gives error about syntax in the control cycle I need to plot only the right sector, something like
If[ sect[[j]] == index, Plot[ list[[j]] ] ].
So I'm stuck here, thanks to anyone will help!

I'm not convinced your data structure is optimal, but here's a sample set of data:
data2 = {
{"stock",
{
Range[6], Range[6, 12],
Range[12, 18]
},
{
Range[18, 24], Range[24, 30],
Range[30, 36]
}
},
{"bank",
Table[Range[i, i + 5], {i, 1, 18, 6}],
Table[Range[i, i + 5], {i, 18, 30, 6}]
}
};
and the Manipulate:
Manipulate[ListPlot[data2[[cat, year, month]]],
{{cat, 1, "Category"}, {1 -> "stock", 2 -> "bank"},
ControlType -> PopupMenu},
{{year, 2, "Year"}, {2 -> "2010", 3 -> "2011"},
ControlType -> PopupMenu},
{{month, 1, "Month"}, {1 -> "Jan", 2 -> "Feb", 3 -> "Mar"},
ControlType -> PopupMenu}]

Related

Is there a way in Kotlin to map through a list, referencing previous values of the new transformation?

Pretty much the title. I want to map through a list to create a new list, but the logic for transforming each element depends on previous values that have been already transformed.
For a simple example, I have a list val myList = [1, 2, 3, 4, 5] and I want to map through each value, where each new value is the sum of the current element plus the previous transformed element. Meaning, I want the result to be [1, 3, 6, 10, 15]. This is not a real scenario, just for sake of example.
I can map through my list but I don't know how to reference the new list that's currently being built:
myList.map { it + list_that's_currently_being_built[i-1] }
runningReduce
fun main() {
val myList = listOf(1, 2, 3, 4, 5)
val result = myList.runningReduce { acc, value -> acc + value }
println(result) // [1, 3, 6, 10, 15]
}

Combining multiple predicates not working

I'm trying to filter certain items out of a list and merge them in the final list in a specific order. The first code snippet seems inefficient since it creates 2 lists for filtering & then iterates over them however that code works. The second snippet is trying to combine both filterings however the map operator is not adding items to otherNums list
Could someone please help me understand why is this happening?
Snippet 1:
fun main() {
val favItem = 0
val list = listOf(11, 12, 13, 2,3,4,5,6,7,10, favItem)
val greaterThan10 = list.filter{item -> item > 10}
val otherNums = list.asSequence().filter{item -> item != favItem}.filter{item -> item < 10}
println(" $greaterThan10") //the list is filled with proper numbers
println("merged list ${greaterThan10.plus(favItem).plus(otherNums)}")
}
Result:
[11, 12, 13]
merged list [11, 12, 13, 0, 2, 3, 4, 5, 6, 7]
Snippet 2:
fun main() {
val favItem = 0
val list = listOf(11, 12, 13, 2,3,4,5,6,7,10, favItem)
val greaterThan10 = mutableListOf<Int>()
val otherNums = list.asSequence().filter{item -> item != favItem}.map{
if(it > 10) {
greaterThan10.add(it)
}
it
}
.filter{item -> item != 10}
println("$greaterThan10") // the list is empty
println("merged list ${greaterThan10.plus(favItem).plus(otherNums)}")
}
Result:
[]
merged list [0, 11, 12, 13, 2, 3, 4, 5, 6, 7]
In your second snippet, greaterThan10 list is empty because of the lazy behavior of sequences, a sequence is iterated only when a terminal operation is encountered like toList() or sum().
In your case, the sequence is iterated when you write .plus(otherNums). List + Sequence produces a List. If you print your greaterThan10 list after printing the merged list, you will find it populated.
Btw, you don't need a Sequence here. Two major cases where sequences are more performant than lists are:
When you have lot of intermediate operations, like map, filter etc.
With Iterable a lot of intermediate Iterables are created which consume more memory,
When you have some kind of a short-circuit operation at the end like take(), contains(), first() etc. i.e. when the entire collection needs not be iterated to get the final result.
As per the docs,
The lazy nature of sequences adds some overhead which may be significant when processing smaller collections or doing simpler computations. Hence, you should consider both Sequence and Iterable and decide which one is better for your case.
For the final solution, I think you can use your snippet 1. That looks good to me, just remove the unnecessary asSequence and combine the two filter into one.
fun main() {
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
val greaterThan10 = list.filter {item -> item > 10}
val otherNums = list.filter { it != favItem && it <= 10 }
println(" $greaterThan10")
println("merged list ${greaterThan10 + favItem + otherNums}")
}
I think using filter is better than minus on lists as the latter has quadratic worst case time complexity (if I remember correctly).
I wrote a small example to demonstrate the difference. Run this a few times to see the difference.
Also, as #IvoBeckers mentioned in the comment,
"If the original list doesn't have a favItem this method will also add one to it. And if the list has multiple of the favItem this method will replace it with a single one."
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
val greaterThan10 = list.filter { it > 10 }
val otherNums = list - greaterThan10.toSet() - favItem
println("greaterThan10: $greaterThan10") // [11, 12, 13]
println("otherNums: $otherNums") // [2, 3, 4, 5, 6, 7, 10]
println("merged list: ${greaterThan10 + favItem + otherNums}")
Edit: replaced .minus(...) with -. Thanks to #Ivo Beckers' comment.
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
val (greaterThan10, otherNums) = list // destructuring assignment
.filter { it != favItem } // filter out favItem
.groupBy { it > 10 } // create two groups
.toSortedMap { o1, _ -> if (o1) -1 else 1 } // sort groups in the order [true, false]
.map { it.value.toList() } // return the two lists
println("greaterThan10: $greaterThan10")
println("otherNums: $otherNums")
println("merged list: ${greaterThan10 + favItem + otherNums}")

c3 charts dynamic bubble size in scatter plot, wrong index

I'm trying to make a chart like with c3.js.
For the bubble size I create an array for each "continent" holding the population as a factor to increase the bubble size. Also the country name is stored in the same manner.
When adding the data points to the chart as well as when adding the bubble sizes/country names to the array, the indices are the same. E.g. col_2[0] in the bubbleInfo array is "China". Also in the data columns col_2[0] and col_2_x[0] are 76 and 12000 which are the values for China.
However, in the section where I dynamically get the bubble radius/country name, the index I get from the function parameter is not the one of the col_2 arrays. Instead I get the index in the order in which the dots are spead along the x-Axis.
E.g. I add for x-Axis China (12000), India(5800), Indonesia(9000) in this order.
I'd expect to get index 1 for India, but I get index 0, because 5800 is the lowest of the x values.
Because of that I cannot properly map the indices on the bubble sizes/country names, since the indices are wrong.
Is this a bug and if so, how can I properly map the bubble sizes/country names then?
Here is the JSFiddle:
var chart_3_bubbleSize = {
"col_2": [10.0, 9.0, 3.9, 2.5, ],
"col_1": [3.0, 2.5, ],
"col_3": [2.5, 5.5, ],
};
...
var chart_3_bubbleInfo = {
"col_2": ["China", "India", "Indonesia", "Japan", ],
"col_1": ["Russia", "Germany", ],
"col_3": ["Mexico", "USA", ],
};
...
columns: [
['col_2', 76, 66, 71, 86],
['col_2_x', 12000, 5800, 9000, 36000],
['col_1', 72, 80.4],
['col_1_x', 25000, 40000],
['col_3', 76, 78],
['col_3_x', 16000, 50000],
],
...
point:
{
r: function(d)
{
/*d.index gives the index according to the order along the x-axis, which leads to wrong result, when trying to map to country names/bubble sizes*/
return 2 * chart_3_bubbleSize[d.id][d.index];
}
},
https://jsfiddle.net/51oLxqyt/1/
The first green bubble in the lower left corner should be India, but it has the label "China" and the bubble size of China, because China is at index 0 in the bubbleInfo and bubbleSize arrays.
There is an not documented attribute data.xSort = false, which keeps the original index, which makes it possible to map more dimension e.g. for scatter charts.
More info here: https://github.com/c3js/c3/issues/547#issuecomment-56292971

bug or i don't understand "evolve"

When using Ramda.remove() by itself the function takes an array and outputs an array:
const grid = {rows: [1, 2, 3]};
R.remove(1, 1, grid.rows) // output: [1,3]
When I use Ramda.remove() as a transformation function in Ramda.evolve() it becomes an object {"0": 1, "1": 2, "2": 3} instead of an array [1,3]:
const grid = {rows: [1, 2, 3]};
R.evolve({
rows: R.remove(1, 1, grid.rows)
})(grid); // output:{"rows": {"0": 1, "1": 2, "2": 3}}
Do I understand evolve correctly or is a bug?
I imagine what you most likely want is
rows: R.remove(1, 1)
That will give you a function from a list to a shortened version of that list.
Just when writing this issue I realized what's wrong. I had to wrap R.remove in a function or bind the args. Basically, I needed to pass the reference to the function.
rows: () => R.remove(1, 1, grid.rows)

Mathematica dynamic to plot matrix data

I am trying to dynamically plot data contained in a matrix with Mathematica 7. The data is contained in it like this, obtained via a chemical model.
[year H He Li C ... C8H14+,Grain- ]
[0 0 0.03 0.009 1E-3 ... 0 ]
[100 .1 0.03 0.009 1E-3 ... 0 ]
[200 .2 0.03 0.009 1E-3 ... 0 ]
[300 .2 0.03 0.009 1E-3 ... 0 ]
[... ... ... ... ... ... ... ]
[1E6 .5 0.03 0.003 1E-8 ... 1E-25 ]
The truth is, the matrix dimensions are 2001*1476 (2000 steps and first line for name, and 1475 compounds + 1 column for year), very heavy.
I am trying to plot any compound with a concentration / year plot. This works
Manipulate[
ListLogLogPlot[data[[All, {1, i}]], PlotLabel -> data[[1, i]] ],
{{i, 2, "Compound"}, 2, compounds, 1}
]
where data is the matrix, and compounds a variable set at the number of modelized compounds (1475 here). "compound" is a label for the slider.
The problem is, the slider moves much to fast as a few centimeters browse through 1400+ items.
I tried to do a drop-down menu with
MenuView[
Table[
ListLogLogPlot[data[[All, {1, i}]],PlotLabel -> data[[1, i]]], {i, 2, compounds}
]
]
It also works, but this is a processor killer process (10+ minutes on a Xeon 16-core server executing 16 kernels), as Mathematica try to graph all plots before displaying any of them. Also the drop-down has no name, just a series of numbers (1 for hydrogen to 1475 for C8H14N+,Grain-), even though the plot has a name.
What I am searching a way to plot a graph only on demand, with a name display in the drop-down list (and if required H by default). OR a field where I can enter the name of the compound. This seems to be possible with Dynamic[ ] command, but I don't manage to make it work properly.
Thanks
Mike's suggestion is a good one but if you don't want to go to the effort of putting it in a database, use the ContinuousAction->False option.
testdata =
Join[{Table[ToString[series[i-1]], {i, 1475}]},
RandomReal[{1., 100.}, {2000, 1476}]];
Manipulate[
ListLogLogPlot[testdata[[All, {1, i}]],
PlotLabel -> testdata[[1, i]]], {{i, 2, "Compound"}, 2, 1475, 1},
ContinuousAction -> False]
To get a popup menu, use the {i,listofvalues} syntax for the controller specification.
Manipulate[
ListLogLogPlot[testdata[[All, {1, i}]],
PlotLabel -> testdata[[1, i]]], {i, Range[2, 1475]},
ContinuousAction -> False]
This works pretty fast on my system. (Two year old MacBook Pro)
A fancier version:
spec = Thread[Range[2, 1476] -> Table[ToString[series[i]], {i, 1475}]];
Manipulate[
ListLogLogPlot[testdata[[All, {1, i}]],
PlotLabel -> testdata[[1, i]]], {{i, 2, "Compound"}, spec},
ContinuousAction -> False]
And if all you want to do is step through the images, click on the little plus next to a slider controller to get more detailed controls.
For entering names in an InputField, you could do something like
compounds = Rest[data[[1]]];
Manipulate[
If[MemberQ[compounds, compound], i = Position[compounds, compound][[1, 1]] + 1];
ListLogLogPlot[data[[All, {1, i}]], PlotLabel -> data[[1, i]]],
{{i, 2}, None},
{{compound, data[[1, 2]], "Compound"}, InputField[#, String] &}]
Here, compounds is a list of all the names of the compounds. The If statement in Manipulate is to check whether the name entered in the InputField is a valid compound or not.
Others have already given you ways to create one big popup list. If you don't want to scroll through a popup list of 1475 compounds, you could consider splitting the popup list into sublists. For example, this would split the whole list of compounds into sublists of n=50 elements which might make it easier to navigate
compounds = Rest[data[[1]]];
With[{n = 50},
Manipulate[
i = 1 + Position[compounds, name][[1, 1]];
ListLogLogPlot[data[[All, {1, i}]], PlotLabel -> data[[1, i]]],
{{i, 2}, None},
{{indexlist, 1, "Indices"},
Table[i -> ToString[(i - 1) n + 1] <> " through " <>
ToString[Min[i n, Length[compounds]]],
{i, Ceiling[Length[compounds]/n]}], PopupMenu},
{{name, compounds[[1]], "Compound"},
compounds[[n (indexlist - 1) + 1 ;;
Min[Length[compounds], n indexlist]]], PopupMenu}
]
]
For example, for
data = Table[Join[{i}, RandomReal[{0, 1}, 1000]], {i, 1000}];
data = Join[{Prepend[Table["list " <> ToString[i], {i, 1000}], "year"]}, data];
this looks like
For data sets of this size I'd recommend (as optimal) storing it all in a database and using DatabaseLink to call stuff as required. Then link your controllers, such as popup menus, to SQLExecute code or other SQL functions. Fragments like this would be the sort of thing that would do the job:
DynamicModule[{x,data, ...},
Column[{
PopupMenu[Dynamic[x], {1 -> "category 1", 2 -> "category 2", 3 -> "category 3", ...}],
Dynamic[
data = SQLExecute[conn, "SELECT * FROM myDatabase.table WHERE my_id = `1`;", {x}];
ListLogLogPlot[data]
]
}]
]
In reality you may want to be adding additional popups and doing joins and so on.
EDIT
Alternative that doesn't use databases but uses input fields as requested:
DynamicModule[{x = "He", rules, y},
rules = Rule ### Transpose[{data[[1, All]], Range[Length[data[[1, All]]]]}];
Column[{
InputField[Dynamic[x], String],
Dynamic[
y = x /. rules;
ListLogLogPlot[data[[All, {1, y}]], PlotLabel -> data[[1, y]]]
]
}]
]
For rules lists of this size you'd probably want to use Dispatch I'd imagine. See how the timing goes for that. It looks like this is some sort of experiment you are running so my first choice remains dumping it into a DB.
FURTHER EDIT
If you're relying on input fields then you will need to account for clumsy typing by inserting a conditional so that Mma only attempts to plot if y is an integer.
If[IntegerQ[y],
ListLogLogPlot,
Spacer[0]
]