Here’s the code, woven in with its output and some comments, block by block:
func MakeAssignment(NewDF dataframe.DataFrame, win fyne.Window,
BT binding.UntypedList,dfnames []string,
tentries []fyne.CanvasObject, header_canvas []fyne.CanvasObject,
ncols int, nrows int) {
var manualassign bool
assignment := []string{}
for _, v := range NewDF.Names() {
if NewDF.Col(v).Type() == series.Int {
-IsThisCat Function-
-IsThisCat Function-
This triggered twice because there are two integer columns.The IsThisCat function only opens a dialog asking the user for some information.It begins by printing -“IsThisCat Function” and ends by printing “USER CHOSE : ” true
or false
.
assignment = append(assignment, "categorical")
} else {
assignment = append(assignment, "numeric")
}
} else if NewDF.Col(v).Type() == series.Float {
assignment = append(assignment, "numeric")
} else if NewDF.Col(v).Type() == series.String {
assignment = append(assignment, "categorical")
} else {
assignment = append(assignment, "categorical")
}
}
manualassign = true
fmt.Println("assignment variable (before loop): ", assignment)
assignment variable (before loop): [categorical numeric categorical numeric]
This did not correctly gather the information from the IsThisCat() function. It should have shown all categorical
, based on my inputs.
for {
if len(assignment) == len(dfnames) {
break
}
}
fmt.Println("assignment variable :", assignment)
This for
loop is meant to be blocking. The length of the assignment
variable will only be equal to the number of column names when the user is finished clicking through the dialogs. This expected behavior is observed, and the following output only appears when the user finishes clicking through the dialogs.
assignment variable : [categorical numeric categorical numeric]
con_scroll := Con_Scroll(dfnames, tentries, header_canvas, ncols, nrows, manualassign, assignment)
BT.Set([]interface{}{con_scroll, NewDF, manualassign, assignment, tentries, header_canvas})
}
Now these above two lines are the strangest, most confusing part. The previous two lines set up the UI. Although it comes after the for
loop executes, and the output prints after the previous command executes, the code takes effect before! This code sets up a UI, which appears on screen before the user is finished clicking through the dialogs.
These next few outputs show the response of the con_scroll
function, which creates a UI element, and the data listener attached to the data binding, BT. The data listener, called NBT in the output, recreates the UI based on the provided information, whenever any data within BT is affected, such as with BT.Set()
Con_scroll function
Column names : [StringVariable Int Variable St2 I2]
Assignment : [categorical numeric categorical numeric]
NBT TRIGGERED
NBT – manual assign
Con_scroll function
Column names : [StringVariable Int Variable St2 I2]
Assignment : [categorical numeric categorical numeric]
..A few lines of irrelevant print statements later…
USER CHOSE : true
USER CHOSE : true
This is the output from the dialogs of the IsThisCat()
function, which should of had to be completed in order to get the data to break the for
loop and complete the code. However, we see that it prints much later.
Any ideas, guys? This one has had me spinning all day. Please ask for more information if you think that would help. Thanks!
EDIT
Here is where the data binding gets its listener, what the listener does, and where the UI is made. I’m cropping out the UI details to shorten.
The first step is that the user opens a file dialog and selects a file. If that goes well, we create a listener that reads data from the data binding and creates a UI element. The data is processed in the dTypes
function. The UI element is created in the Con_Scroll()
function. The UI element is placed into the et
container.
et := container.New(layout.NewStackLayout())
BT := binding.NewUntypedList()
dataSlate := structs.TD{}
var dTypes structs.TD
start_path := Get_Start_Path()
fdialog := widget.NewButton("", func() {
FPATH, errZen := zenity.SelectFile(
zenity.Filename(start_path),
zenity.FileFilters{
{"csv or xlsx files", []string{"*.csv", "*.xlsx"}, true},
{"just xlsx files", []string{"*.xlsx"}, true},
{"just csv files", []string{"*.csv"}, true},
})
if errZen == nil {
var BTinit []interface{}
errBT1 := BT.Set(BTinit)
fmt.Print(errBT1)
nbt := binding.NewDataListener(func() {
fmt.Println("NBT TRIGGERED")
currBT, emptyError := BT.Get()
if emptyError == nil && len(currBT) > 0 {
switch NewDF := currBT[1].(type) {
case dataframe.DataFrame:
switch assignment := currBT[3].(type) {
case []string:
switch manualassign := currBT[2].(type) {
case bool:
if !manualassign {
fmt.Println("NBT - auto assign")
switch dfpInter := currBT[0].(type) {
case *fyne.Container:
dTypes = Typify(NewDF, category_to_entry_ratio, manualassign, assignment)
et.RemoveAll()
et.Add(dfpInter)
}
} else {
fmt.Println("NBT - manual assign")
switch tentries := currBT[4].(type) {
case []fyne.CanvasObject:
switch header_canvas := currBT[5].(type) {
case []fyne.CanvasObject:
con_scroll := Con_Scroll(NewDF.Names(), tentries, header_canvas, NewDF.Ncol(), len(NewDF.Records()), manualassign, assignment)
dTypes = Typify(NewDF, category_to_entry_ratio, manualassign, assignment)
et.RemoveAll()
et.Add(con_scroll)
}
}
}
}
}
case string:
try_again := dialog.NewCustom("No Data", "Close", widget.NewLabel(NewDF), w2)
try_again.Show()
et.RemoveAll()
default:
et.Add(widget.NewLabel("NOT WORKING"))
}
}
})
BT.AddListener(nbt)
callFile(FPATH, w2, BT)
In the callFile()
function, we take the data out and put it into the binding. This should trigger the listener, nbt.
//a bunch of stuff that uses dTypes.
funcButton := widget.NewButton("Analyze", func() {
if ....//dTypes is not empty {
//trigger a function based on dTypes
//trigger another listener based on the result of the previous function
w2.Show() //the window is called w2
}
})
plaque := container.NewBorder(nil, funcButton, nil, fdialog, instructions2)
minibar := minitools.MiniToolBar(BT, w2)
//skipping a lot more stuff that isn't relevant
cont := container.NewBorder(et,plaque,....other stuff)
return cont, dataSlate
The funcButton
function should really trigger a different result based on MakeAssignment()
above, but it does not. Likewise, minibar should also reflect the user choices in MakeAssignment()
, but it does not. Like I said before the edit, it appears to submit the results before the user makes the choices.
In case it’s helpful, here’s where the user input is collected. As already explained, the output shows that the function starts right away but waits for everything else to complete before completing itself, even though it is needed to break the for loop.
func IsThisCat(colname string, col series.Series, win fyne.Window) bool {
fmt.Println("-IsThisCat Function-")
//hint_text := "MeMeY is pretty smart at determining which variablesnare categorical and which are numeric.nBut you probably know your dataset better than anyone else."
itc_lab := widget.NewFormItem("", widget.NewLabel("In other words, does each number represent something other than a number?"))
prev := container.NewVBox()
for k, v := range col.Records() {
if k > 5 {
break
}
//prev.Add(widget.NewLabelWithStyle(col.Records()[k], fyne.TextAlignCenter, fyne.TextStyle{Monospace: true}))
prev.Add(widget.NewLabel(v))
}
itc_prev := widget.NewFormItem(colname, prev)
var itc_list []*widget.FormItem
itc_list = append(itc_list, itc_lab)
itc_list = append(itc_list, itc_prev)
var is_cat bool
itc := dialog.NewForm("Is "+colname+" a categorical variable?", "Yes", "No", itc_list, func(b bool) {
is_cat = b
fmt.Println("USER CHOSE :", b)
}, win)
itc.Resize(fyne.NewSquareSize(400))
itc.Show()
return is_cat
}
3