Mongo Sort Documents by value in array - arrays

I have a list of Students. Each one has an array of points they've earned by category in an array named lightTrail. I want the top 5 people with the most behavior points which is shown at index 1 in the lightTrail array. If it is a tie the second sort field is their total points which is shown at index 0.
Here is what I tried:
db.students.aggregate([{
$project: {
fname: 1,
surname: 1,
lightTrails: 1,
'_id': 0
}
},
{
$sort: {
"lightTrails.1": -1,
"lightTrails.0": -1
}
}, {
$limit: 5
}
], {
allowDiskUse: true
})
This is the result I wanted:
{
"fname": "Jim",
surname: "Jones",
lightTrails: [200, 70, 30, 30, 15, 15, 40]
}, {
"fname": "Sean",
surname: "Marx",
lightTrails: [180, 50, 50, 20, 20, 15, 25]
}, {
"fname": "Todd",
surname: "Lull",
lightTrails: [150, 40, 60, 15, 15, 10, 10]
}, {
"fname": "Flynn",
surname: "Moore",
lightTrails: [100, 40, 25, 15, 5, 10, 5]
}, {
"fname": "Al",
surname: "Ryan",
lightTrails: [80, 20, 20, 10, 10, 10, 10]
}
The result I got was just 5 students no order:
{
"fname": "Flynn",
surname: "Moore",
lightTrails: [100, 40, 25, 15, 5, 10, 5]
}, {
"fname": "Jim",
surname: "Jones",
lightTrails: [200, 70, 30, 30, 15, 15, 40]
}, {
"fname": "Al",
surname: "Ryan",
lightTrails: [80, 20, 20, 10, 10, 10, 10]
}, {
"fname": "Todd",
surname: "Lull",
lightTrails: [150, 40, 60, 15, 15, 10, 10]
}, {
"fname": "Sean",
surname: "Marx",
lightTrails: [180, 50, 50, 20, 20, 15, 25]
}
I found 2 similar questions but one was for an array of documents which didn't work for me and the other wasn't really asking the same question at all.

You can achieve this by find query. No need to use aggregation.
Query:
db.students.find({},{fname:1,surname:1,lightTrails:1,_id:0}).sort({"lightTrails.0":-1,"lightTrails.1":-1}).limit(5)
Result:
{ "fname" : "Jim", "surname" : "Jones", "lightTrails" : [ 200, 70, 30, 30, 15, 15, 40 ] }
{ "fname" : "Sean", "surname" : "Marx", "lightTrails" : [ 180, 50, 50, 20, 20, 15, 25 ] }
{ "fname" : "Todd", "surname" : "Lull", "lightTrails" : [ 150, 40, 60, 15, 15, 10, 10 ] }
{ "fname" : "Flynn", "surname" : "Moore", "lightTrails" : [ 100, 40, 25, 15, 5, 10, 5 ] }
{ "fname" : "Al", "surname" : "Ryan", "lightTrails" : [ 80, 20, 20, 10, 10, 10, 10 ] }

Related

How can I add padding bottom after the x-axis label using apexchart

I am having this Apex chart in my react app ,
What I want to do is add more space between the x-axis label which is the month labels and the series name below it (Session Duration, Page Views, Total Visits). How can I achieve that
This is my code below
............................................................................................................................
class ApexChart extends React.Component {
constructor(props) {
super(props);
this.state = {
series: [{
name: "Session Duration",
data: [45, 52, 38, 24, 33, 26, 21, 20, 6, 8, 15, 10]
},
{
name: "Page Views",
data: [35, 41, 62, 42, 13, 18, 29, 37, 36, 51, 32, 35]
},
{
name: 'Total Visits',
data: [87, 57, 74, 99, 75, 38, 62, 47, 82, 56, 45, 47]
}
],
options: {
chart: {
height: 350,
type: 'line',
zoom: {
enabled: false
},
},
dataLabels: {
enabled: false
},
stroke: {
width: [5, 7, 5],
curve: 'straight',
dashArray: [0, 8, 5]
},
title: {
text: 'Page Statistics',
align: 'left'
},
legend: {
tooltipHoverFormatter: function(val, opts) {
return val + ' - ' + opts.w.globals.series[opts.seriesIndex][opts.dataPointIndex] + ''
}
},
markers: {
size: 0,
hover: {
sizeOffset: 6
}
},
xaxis: {
categories: ['01 Jan', '02 Jan', '03 Jan', '04 Jan', '05 Jan', '06 Jan', '07 Jan', '08 Jan', '09 Jan',
'10 Jan', '11 Jan', '12 Jan'
],
},
tooltip: {
y: [
{
title: {
formatter: function (val) {
return val + " (mins)"
}
}
},
{
title: {
formatter: function (val) {
return val + " per session"
}
}
},
{
title: {
formatter: function (val) {
return val;
}
}
}
]
},
grid: {
borderColor: '#f1f1f1',
}
},
};
}
render() {
return (
<div id="chart">
<ReactApexChart options={this.state.options} series={this.state.series} type="line" height={350} />
</div>
);
}
}
Based on some fiddling around with the Appchart demo, found 2 options that seem to provide result here.
Both use the legend key inside options, which you have in your code
You can add specific height to the legend container
legend: {
height: 100
}
This will allow you to add margin to each legend.
legend: {
itemMargin: {
horizontal: 20
}
}
Hopefully someone with more experience with AppChart can provide a better solution but till then you can look into these.

SwiftUI: I have a list which when I click on an object I want to go into a detail view where I can select or deselect the current object

I can set up the list fine and even have a select or deselect button in the detail view (CardView). The problem I encounter is when I click select I want to add it to an array (cardSelected). If "name3" is the 1st in the list how can I find out the index to add to the cardSelected array?
I'm new to programming so looking for some guidance. Thanks
import Foundation
import SwiftUI
class Cards: ObservableObject {
#Published var cardSelected = [gameCards]()
#Published var playerCards = [gameCards]()
#Published var playerGameCards = [
gameCards(id: 1, name: "name1", attack: 92, defence: 49, gameControl: 60, creativity: 72, legend: 4),
gameCards(id: 2, name: "name2", attack: 87, defence: 40, gameControl: 65, creativity: 80, legend: 2),
gameCards(id: 3, name: "name3", attack: 43, defence: 93, gameControl: 40, creativity: 45, legend: 3),
gameCards(id: 4, name: "name4", attack: 88, defence: 51, gameControl: 80, creativity: 92, legend: 5),
gameCards(id: 5, name: "name5", attack: 85, defence: 51, gameControl: 72, creativity: 81, legend: 3),
gameCards(id: 6, name: "name6", attack: 91, defence: 38, gameControl: 72, creativity: 89, legend: 5),
gameCards(id: 7, name: "name7", attack: 34, defence: 95, gameControl: 40, creativity: 50, legend: 5),
gameCards(id: 8, name: "name8", attack: 86, defence: 63, gameControl: 89, creativity: 84, legend: 4),
gameCards(id: 9, name: "name9", attack: 90, defence: 30, gameControl: 50, creativity: 83, legend: 5),
gameCards(id: 10, name: "name10", attack: 32, defence: 92, gameControl: 42, creativity: 32, legend: 4)
]
}
struct gameCards: Identifiable {
let id: Int
let name: String
let attack: Int
let defence: Int
let gameControl: Int
let creativity: Int
let legend: Int
import SwiftUI
struct CardView: View{
var carddetail: String
#EnvironmentObject var cardselected: Cards
#State var cardSelect: Bool = false
var body: some View{
ZStack{
VStack{
Text(carddetail)
Spacer()
if cardSelect == false {
Button(action:{
self.cardSelect = true
below ?? is where I want to add the index but don't know how to programmatically find it.
self.cardselected.cardSelected.append(self.cardselected.playerCards[??])
print("\([self.carddetail])")
print("\([self.cardselected.cardSelected.description])")
}){
if cardSelect == false {
Image(systemName: "star")
}
if cardSelect == true{
Image(systemName: "star.fill")
}
}
}
if cardSelect == true {
Button(action:{
self.cardSelect = false
}){
if cardSelect == false {
Image(systemName: "star")
}
if cardSelect == true{
Image(systemName: "star.fill")
}
}
}
Spacer()
}
}
}
}
struct ContentView: View {
#EnvironmentObject var playerList: Cards
var body: some View {
NavigationView{
ZStack{
Image("Background").resizable().edgesIgnoringSafeArea(.all)
VStack{
Image("FLTitle").resizable().frame(width: 400, height: 100)
Spacer()
Text("Collected Cards")
Text("Choose 5")
ScrollView(.horizontal){
HStack{
Image("Back")
Image("Back")
Image("Back")
Image("Back")
Image("Back")
}.padding(.horizontal)
}
Spacer()
HStack{
NavigationView{
List(playerList.playerCards) {gc in
NavigationLink(destination: CardView(carddetail: gc.name)){
Text("\(gc.name)")
}
}.navigationBarTitle("Card detail").font(.body)
}.padding(.leading).frame(width: UIScreen.main.bounds.size.width/2, height: 200)
Text("Opposition").padding(.trailing).frame(width: UIScreen.main.bounds.size.width/2, height: 200).background(Color.red)
}
Spacer()
}
}
}.navigationBarTitle("", displayMode: .inline).navigationBarBackButtonHidden(true).navigationBarHidden(true)
}
}
let data = Cards()
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(data)
}
}
When creating the List you can use ForEach to access the index and then pass to CardView
List {
ForEach(0..<playerList.playerCards.count) { index in
NavigationLink(destination: CardView(carddetail: self.playerList.playerCards[index].name,
index: index)) {
Text("\(self.playerList.playerCards[index].name)")
}
}.navigationBarTitle("Card detail").font(.body)
}

SwiftUI: I want to use the information in my array but I'm unable to find the right command

I'm very new to programming and I'm having trouble with the more complex aspects. I am trying to use a data set called playerCameCards and randomly add 5 of these to playerCards. I have managed to do that but I want to display name: of the last added element but I can't figure out how to do it. I'd be grateful for some help Below is my code.
import Foundation
import SwiftUI
class Cards: ObservableObject {
#Published var playerCards = [gameCards]()
#Published var playerGameCards = [
gameCards(id: 1, name: "name1", attack: 92, defence: 49, gameControl: 60, creativity: 72, legend: 4),
gameCards(id: 2, name: "name2", attack: 87, defence: 40, gameControl: 65, creativity: 80, legend: 2),
gameCards(id: 3, name: "name3", attack: 43, defence: 93, gameControl: 40, creativity: 45, legend: 3),
gameCards(id: 4, name: "name4", attack: 88, defence: 51, gameControl: 80, creativity: 92, legend: 5),
gameCards(id: 5, name: "name5", attack: 85, defence: 51, gameControl: 72, creativity: 81, legend: 3),
gameCards(id: 6, name: "name6", attack: 91, defence: 38, gameControl: 72, creativity: 89, legend: 5),
gameCards(id: 7, name: "name7", attack: 34, defence: 95, gameControl: 40, creativity: 50, legend: 5),
gameCards(id: 8, name: "name8", attack: 86, defence: 63, gameControl: 89, creativity: 84, legend: 4),
gameCards(id: 9, name: "name9", attack: 90, defence: 30, gameControl: 50, creativity: 83, legend: 5),
gameCards(id: 10, name: "name10", attack: 32, defence: 92, gameControl: 42, creativity: 32, legend: 4)
]
}
struct gameCards: Identifiable {
let id: Int
let name: String
let attack: Int
let defence: Int
let gameControl: Int
let creativity: Int
let legend: Int
}
import SwiftUI
struct ContentView: View {
#EnvironmentObject var cardData: Cards
#State var firstTime: Bool = false
#State var currentCard: String = "Back"
var body: some View {
ZStack{
VStack{
Spacer()
Text("Lets open your 1st cards").background(Color.white).font(.title)
Spacer()
Below is where I want show the name e.g. "name1" from the last element added to my playerCards array. I may want to make this an image in the future and use the ID: to display the corresponding image but I'm unable to access the types in my array
Text("I want to show the "name" of the element in the last array I've just used").frame(width: 200, height: 200).background(Color.blue)
Spacer()
Button(action:{
if self.cardData.playerCards.count <= 4{
self.cardData.playerCards.append(self.cardData.playerGameCards.randomElement()!)
print("\([self.cardData.playerCards.last])")
}
if self.cardData.playerCards.count > 4 {
self.firstTime = true
}
}){
if self.cardData.playerCards.count <= 4 {
Image("Click").renderingMode(.original).resizable().frame(width: 100, height: 100)
}
else{
NavigationLink(destination: ContentView()){Image("Continue").renderingMode(.original).resizable().frame(width: 100, height: 100)
}
}
}
}
}
}
}
This is how to embed a value in a String in Swift:
if self.cardData.playerCards.last != nil {
Text("I want to show the \(self.cardData.playerCards.last!.name) of the element in the last array I've just used")
}

Working with Charts in motion [Animating chart]

I have created a areaspline chart using highcharts library and making it animated with play/pause button transition between weeks of data
Ref. https://www.highcharts.com/blog/tutorials/176-charts-in-motion/
jsfiddle Ref. https://jsfiddle.net/larsac07/wkev75nL/?utm_source=website&utm_medium=embed&utm_campaign=wkev75nL
in the above example, we are animating the chart week wise
dataSet used :
dataSequence = [
{
name: 'Week 1',
data: [1, 2, 2, 1, 1, 2, 2]
}, {
name: 'Week 2',
data: [6, 12, 2, 3, 3, 2, 2]
}, {
name: 'Week 3',
data: [4, 5, 6, 5, 5, 4, 9]
}, {
name: 'Week 4',
data: [5, 5, 6, 6, 5, 6, 6]
}, {
name: 'Week 5',
data: [6, 7, 7, 6, 6, 6, 7]
}, {
name: 'Week 6',
data: [8, 9, 9, 8, 8, 8, 9]
}, {
name: 'Week 7',
data: [9, 10, 4, 10, 9, 9, 9]
}, {
name: 'Week 8',
data: [1, 10, 10, 10, 10, 11, 11]
}, {
name: 'Week 9',
data: [11, 11, 12, 12, 12, 11, 11]
}
]
I don't want change chart
on play button click I want animate the data points 11 data point for week1 to same data point but different value on y axis for week2
xAxis = ["week1", "Week2", ..... ],
yAxis = [[1,2,3,4,5,6,7,8,9,10,11], [3,5,7,8,2,1,5,7,6,1,10], ....]
on the play button it would transit between week1 then will go to week 2 and so till last week number available.
Trying to have something like this Ref. https://aatishb.com/covidtrends/
this chart is plotted using this dataset for series
Highcharts.chart("container", {
chart: {
type: "areaspline"
},
tooltip: {
shared: true,
valueSuffix: " units"
},
xAxis: {
categories: [
"Week 1",
"Week 2",
"Week 3",
"Week 4",
"Week 5",
"Week 6",
"Week 7"
]
},
yAxis: {
title: {
text: "Index"
}
},
legend: {
layout: "horizontal",
align: "right",
verticalAlign: "top",
x: 50,
y: 50,
floating: true,
borderWidth: 1,
backgroundColor:
(Highcharts.theme && Highcharts.theme.legendBackgroundColor) ||
"#FFFFFF"
},
plotOptions: {
areaspline: {
fillOpacity: 0.5
}
},
credits: {
enabled: false
},
series: [
{
name: "By week",
data: dataSequence[value].data.slice()
},
{
type: "spline",
name: "Topic 1",
data: [3, 2, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 2",
data: [1, 5, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 3",
data: [3, 7, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 4",
data: [5, 1, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 5",
data: [7, 3, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 6",
data: [9, 2, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 7",
data: [11, 8, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 8",
data: [13, 11, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 9",
data: [15, 7, 1, 3, 4, 7, 8]
},
{
type: "spline",
name: "Topic 10",
data: [7, 5, 1, 3, 4, 7, 8]
}
],
title: {
text: ""
},
subtitle: {
text: "Efficiency Index of Topics"
}
});
this my update function in react
update(increment) {
var input = $("#play-range")[0];
var output = $("#play-output")[0];
if (increment) {
input.value = parseInt(input.value) + increment;
}
output.innerHTML = this.state.dataSequence[input.value].name;
this.setState({
value: input.value
});
if (input.value >= input.max) {
// Auto-pause
this.pause();
this.setState(
{
value: 0
},
() => {
output.innerHTML = this.state.dataSequence[0].name;
}
);
}
}
the whole chart is plotted at once, I need something that it should transit
first, it plots all data points for week1 then week 2 after that week 3 when I click on the play button
You need to start with an empty data and use addPoint method in the update function:
function update(increment) {
var input = $('#play-range')[0],
output = $('#play-output')[0],
increment;
chart.series[0].addPoint(dataSequence[input.value].data[actualPointIndex]);
actualPointIndex += increment;
if (actualPointIndex === 6) {
actualPointIndex = 0;
input.value = parseInt(input.value) + increment;
}
output.innerHTML = dataSequence[input.value].name; // Output value
if (input.value >= input.max) { // Auto-pause
pause($('#play-pause-button')[0]);
}
}
Live demo: https://jsfiddle.net/BlackLabel/stpxyfca/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#addPoint

Adding labels to both ends of axis google charts

I've built a bubble chart on quadrant graph using google-charts in reactjs but I can only had two labels on my axis and I need four.
I've tried fiddling with the code but unsuccessfully. I don't want to append dummy data and additional series elements. Is overlay the only option to add axis?
<Chart
width={"800px"}
height={"600px"}
chartType="BubbleChart"
loader={<div>Loading Chart</div>}
data={[
["Age", "Weight", "4", "Group", "Size"],
["Name", -12, 34, 1, 7],
["Name", -5.5, 6, 1, 8],
["Name", 22, 35, 1, 4],
["Name", 14, 4, 2, 5],
["Name", -5, -5, 2, 6],
["Name", 15, 34, 3, 1],
["Name4", 7, -21, 4, 22]
]}
options={{
bubble: {},
chartArea: { left: 20, top: 0, width: "90%", height: "95%" },
colors: ["red", "green", "yellow", "blue"],
hAxis: {
title: "Low Importance",
ticks: "none",
baseline: 0,
ticks: ["none"],
minValue: -50,
gridlines: { count: 0 },
maxValue: 50
},
vAxis: {
title: "Low Urgency",
baseline: 0,
ticks: ["none"],
minValue: -50,
gridlines: { count: 0 },
maxValue: 50
},
legend: "none"
}}
/>;
As you can see in the graph below, I can only get left and bottom labels but not top and right. Any ideas how I could achieve that using google-chart library for reactjs?

Resources