Related
Dears,
How to get character's equivalent from another TextInput using PySimpleGUI?
Let me explain: Suppose I have those sets of data , set A and Set B, my query is once I write one characters in TextInput 1 from Set A I'll get automatically it's equivalent in Set B;
For example Set A : A, B, C, D, ........, Z
Set B : 1, 2, 3,4, ..........,26
So if I write ABC in TextInut A --> I'll get : 123 in TextInput B
Thanks in advance
import PySimpleGUI as sg
enter image description here
My apologies if I misunderstand your question.
First, special characters, like ☯, ∫, β, etc., are just Unicode characters. You can type them directly into your editor or use the Unicode escape codes. You might see this question for more help.
Second, it is unclear when you want to make this mapping. It is easiest if you type characters and then map at the end. If you want to do interactively that is harder. You can get each individual keyboard event; see (this answer)[https://stackoverflow.com/a/74214510/1320510] for an example. Because I know of no way of the exact position, you might be better getting the events, and writing the display to a second label. I would need to more a bit more about what you are doing.
Keep hacking! Keep notes.
Charles
Set option enable_events=True to A, map each char in values[A] by dictionary {'A':'1', ...}, then update B with the result when event A.
Demo Code
import string
import PySimpleGUI as sg
table = {char:str(i+1) for i, char in enumerate(string.ascii_uppercase)}
layout = [
[sg.Input(enable_events=True, key='-IN1-')],
[sg.Input(key='-IN2-')],
]
window = sg.Window('Main Window', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == '-IN1-':
text1 = values['-IN1-']
text2 = ''.join([table[char] if char in string.ascii_uppercase else char for char in text1])
window['-IN2-'].update(text2)
window.close()
For different case, like table = {'a':'apple', 'b':'banana', 'c':'orange'}
import string
import PySimpleGUI as sg
table = {'a':'apple', 'b':'banana', 'c':'orange'}
layout = [
[sg.Input(enable_events=True, key='-IN1-')],
[sg.Input(key='-IN2-')],
]
window = sg.Window('Main Window', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == '-IN1-':
text1 = values['-IN1-']
text2 = ''.join([table[char] if char in table else char for char in text1])
window['-IN2-'].update(text2)
window.close()
Let's say I want to process a variadic function which alternately gets passed start and end values of 1 or more intervals and it should return a range of random values in those intervals. You can imagine the input to be a flattened sequence of tuples, all tuple elements spread over one single range.
import std.meta; //variadic template predicates
import std.traits : isFloatingPoint;
import std.range;
auto randomIntervals(T = U[0], U...)(U intervals)
if (U.length/2 > 0 && isFloatingPoint!T && NoDuplicates!U.length == 1) {
import std.random : uniform01;
T[U.length/2] randomValues;
// split and iterate over subranges of size 2
foreach(i, T start, T end; intervals.chunks(2)) { //= intervals.slide(2,2)
randomValues[i] = uniform01 * (end - start) + start,
}
return randomValues.dup;
}
The example is not important, I only use it for explanation. The chunk size could be any finite positive size_t, not only 2 and changing the chunk size should only require changing the number of loop-variables in the foreach loop.
In this form above it will not compile since it would only expect one argument (a range) to the foreach loop. What I would like is something which rather automatically uses or infers a sliding-window as a tuple, derived from the number of given loop-variables, and fills the additional variables with next elements of the range/array + allows for an additional index, optionally. According to the documentation a range of tuples allows destructuring of the tuple elements in place into foreach-loop-variables so the first thing, I thought about, is turning a range into a sequence of tuples but didn't find a convenience function for this.
Is there a simple way to loop over destructured subranges (with such a simplicity as shown in my example code) together with the index? Or is there a (standard library) function which does this job of splitting a range into enumerated tuples of equal size? How to easily turn the range of subranges into a range of tuples?
Is it possible with std.algorithm.iteration.map in this case (EDIT: with a simple function argument to map and without accessing tuple elements)?
EDIT: I want to ignore the last chunk which doesn't fit into the entire tuple. It just is not iterated over.
EDIT: It's not, that I couldn't program this myself, I only hope for a simple notation because this use case of looping over multiple elements is quite useful. If there is something like a "spread" or "rest" operator in D like in JavaScript, please let me know!
Thank you.
(Added as a separate answer because it's significantly different from my previous answer, and wouldn't fit in a comment)
After reading your comments and the discussion on the answers thus far, it seems to me what you seek is something like the below staticChunks function:
unittest {
import std.range : enumerate;
size_t index = 0;
foreach (i, a, b, c; [1,2,3,1,2,3].staticChunks!3.enumerate) {
assert(a == 1);
assert(b == 2);
assert(c == 3);
assert(i == index);
++index;
}
}
import std.range : isInputRange;
auto staticChunks(size_t n, R)(R r) if (isInputRange!R) {
import std.range : chunks;
import std.algorithm : map, filter;
return r.chunks(n).filter!(a => a.length == n).map!(a => a.tuplify!n);
}
auto tuplify(size_t n, R)(R r) if (isInputRange!R) {
import std.meta : Repeat;
import std.range : ElementType;
import std.typecons : Tuple;
import std.array : front, popFront, empty;
Tuple!(Repeat!(n, ElementType!R)) result;
static foreach (i; 0..n) {
result[i] = r.front;
r.popFront();
}
assert(r.empty);
return result;
}
Note that this also deals with the last chunk being a different size, if only by silently throwing it away. If this behavior is undesirable, remove the filter, and deal with it inside tuplify (or don't, and watch the exceptions roll in).
chunks and slide return Ranges, not tuples. Their last element can contain less than the specified size, whereas tuples have a fixed compile time size.
If you need destructuring, you have to implement your own chunks/slide that return tuples. To explicitly add an index to the tuple, use enumerate. Here is an example:
import std.typecons, std.stdio, std.range;
Tuple!(int, int)[] pairs(){
return [
tuple(1, 3),
tuple(2, 4),
tuple(3, 5)
];
}
void main(){
foreach(size_t i, int start, int end; pairs.enumerate){
writeln(i, ' ', start, ' ', end);
}
}
Edit:
As BioTronic said using map is also possible:
foreach(i, start, end; intervals
.chunks(2)
.map!(a => tuple(a[0], a[1]))
.enumerate){
Your question has me a little confused, so I'm sorry if I've misunderstood. What you're basically asking is if foreach(a, b; [1,2,3,4].chunks(2)) could work, right?
The simple solution here is to, as you say, map from chunk to tuple:
import std.typecons : tuple;
import std.algorithm : map;
import std.range : chunks;
import std.stdio : writeln;
unittest {
pragma(msg, typeof([1,2].chunks(2).front));
foreach(a, b; [1,2,3,4].chunks(2).map!(a => tuple(a[0], a[1]))) {
writeln(a, ", ", b);
}
}
At the same time with BioTronic, I tried to code some own solution to this problem (tested on DMD). My solution works for slices (BUT NOT fixed-size arrays) and avoids a call to filter:
import std.range : chunks, isInputRange, enumerate;
import std.range : isRandomAccessRange; //changed from "hasSlicing" to "isRandomAccessRange" thanks to BioTronics
import std.traits : isIterable;
/** turns chunks into tuples */
template byTuples(size_t N, M)
if (isRandomAccessRange!M) { //EDITED
import std.meta : Repeat;
import std.typecons : Tuple;
import std.traits : ForeachType;
alias VariableGroup = Tuple!(Repeat!(N, ForeachType!M)); //Tuple of N repititions of M's Foreach-iterated Type
/** turns N consecutive array elements into a Variable Group */
auto toTuple (Chunk)(Chunk subArray) #nogc #safe pure nothrow
if (isInputRange!Chunk) { //Chunk must be indexable
VariableGroup nextLoopVariables; //fill the tuple with static foreach loop
static foreach(index; 0 .. N) {
static if ( isRandomAccessRange!Chunk ) { // add cases for other ranges here
nextLoopVariables[index] = subArray[index];
} else {
nextLoopVariables[index] = subArray.popFront();
}
}
return nextLoopVariables;
}
/** returns a range of VariableGroups */
auto byTuples(M array) #safe pure nothrow {
import std.algorithm.iteration : map;
static if(!isInputRange!M) {
static assert(0, "Cannot call map() on fixed-size array.");
// auto varGroups = array[].chunks(N); //fixed-size arrays aren't slices by default and cannot be treated like ranges
//WARNING! invoking "map" on a chunk range from fixed-size array will fail and access wrong memory with no warning or exception despite #safe!
} else {
auto varGroups = array.chunks(N);
}
//remove last group if incomplete
if (varGroups.back.length < N) varGroups.popBack();
//NOTE! I don't know why but `map!toTuple` DOES NOT COMPILE! And will cause a template compilation mess.
return varGroups.map!(chunk => toTuple(chunk)); //don't know if it uses GC
}
}
void main() {
testArrayToTuples([1, 3, 2, 4, 5, 7, 9]);
}
// Order of template parameters is relevant.
// You must define parameters implicitly at first to be associated with a template specialization
void testArrayToTuples(U : V[], V)(U arr) {
double[] randomNumbers = new double[arr.length / 2];
// generate random numbers
foreach(i, double x, double y; byTuples!2(arr).enumerate ) { //cannot use UFCS with "byTuples"
import std.random : uniform01;
randomNumbers[i] = (uniform01 * (y - x) + x);
}
foreach(n; randomNumbers) { //'n' apparently works despite shadowing a template parameter
import std.stdio : writeln;
writeln(n);
}
}
Using elementwise operations with the slice operator would not work here because uniform01 in uniform01 * (ends[] - starts[]) + starts[] would only be called once and not multiple times.
EDIT: I also tested some online compilers for D for this code and it's weird that they behave differently for the same code. For compilation of D I can recommend
https://run.dlang.io/ (I would be very surprised if this one wouldn't work)
https://www.mycompiler.io/new/d (but a bit slow)
https://ideone.com (it works but it makes your code public! Don't use with protected code.)
but those didn't work for me:
https://tio.run/#d2 (didn't finish compilation in one case, otherwise wrong results on execution even when using dynamic array for the test)
https://www.tutorialspoint.com/compile_d_online.php (doesn't compile the static foreach)
I have one question though. I heard from someone that in R, you can use extra packages to extract the decision rules implemented in RF, I try to google the same thing in python but without luck, if there is any help on how to achieve that.
thanks in advance!
Assuming that you use sklearn RandomForestClassifier you can find the invididual decision trees as .estimators_. Each tree stores the decision nodes as a number of NumPy arrays under tree_.
Here is some example code which just prints each node in order of the array. In a typical application one would instead traverse by following the children.
import numpy
from sklearn.model_selection import train_test_split
from sklearn import metrics, datasets, ensemble
def print_decision_rules(rf):
for tree_idx, est in enumerate(rf.estimators_):
tree = est.tree_
assert tree.value.shape[1] == 1 # no support for multi-output
print('TREE: {}'.format(tree_idx))
iterator = enumerate(zip(tree.children_left, tree.children_right, tree.feature, tree.threshold, tree.value))
for node_idx, data in iterator:
left, right, feature, th, value = data
# left: index of left child (if any)
# right: index of right child (if any)
# feature: index of the feature to check
# th: the threshold to compare against
# value: values associated with classes
# for classifier, value is 0 except the index of the class to return
class_idx = numpy.argmax(value[0])
if left == -1 and right == -1:
print('{} LEAF: return class={}'.format(node_idx, class_idx))
else:
print('{} NODE: if feature[{}] < {} then next={} else next={}'.format(node_idx, feature, th, left, right))
digits = datasets.load_digits()
Xtrain, Xtest, ytrain, ytest = train_test_split(digits.data, digits.target)
estimator = ensemble.RandomForestClassifier(n_estimators=3, max_depth=2)
estimator.fit(Xtrain, ytrain)
print_decision_rules(estimator)
Example outout:
TREE: 0
0 NODE: if feature[33] < 2.5 then next=1 else next=4
1 NODE: if feature[38] < 0.5 then next=2 else next=3
2 LEAF: return class=2
3 LEAF: return class=9
4 NODE: if feature[50] < 8.5 then next=5 else next=6
5 LEAF: return class=4
6 LEAF: return class=0
...
We use something similar in emlearn to compile a Random Forest to C code.
After investing good amount of searching on net for this topic, I am ending up here if I can get some pointer . please read further
After analyzing Spark 2.0 I concluded polynomial regression is not possible with spark (spark alone), so is there some extension to spark which can be used for polynomial regression?
- Rspark it could be done (but looking for better alternative)
- RFormula in spark does prediction but coefficients are not available (which is my main requirement as I primarily interested in coefficient values)
Polynomial regression is just another case of a linear regression (as in Polynomial regression is linear regression and Polynomial regression). As Spark has a method for linear regression, you can call that method changing the inputs in such a way that the new inputs are the ones suited to polynomial regression. For instance, if you only have one independent variable x, and you want to do quadratic regression, you have to change your independent input matrix for [x x^2].
I would like to add some information to #Mehdi Lamrani’s answer :
If you want to do a polynomial linear regression in SparkML, you may use the class PolynomialExpansion.
For information check the class in the SparkML Doc
or in the Spark API Doc
Here is an implementation example:
Let's assume we have a train and test datasets, stocked in two csv files, with headers containing the neames of the columns (features, label).
Each data set contains three features named f1,f2,f3, each of type Double (this is the X matrix), as well as a label feature (the Y vector) named mylabel.
For this code I used Spark+Scala:
Scala version : 2.12.8
Spark version 2.4.0.
We assume that SparkML library was already downloaded in build.sbt.
First of all, import librairies :
import org.apache.spark.ml.{Pipeline, PipelineModel}
import org.apache.spark.ml.linalg.{Vector, Vectors}
import org.apache.spark.ml.regression.LinearRegression
import org.apache.spark.mllib.evaluation.RegressionMetrics
import org.apache.spark.sql.{DataFrame, SparkSession}
import org.apache.spark.sql.functions.udf
import org.apache.spark.{SparkConf, SparkContext}
Create Spark Session and Spark Context :
val ss = org.apache.spark.sql
.SparkSession.builder()
.master("local")
.appName("Read CSV")
.enableHiveSupport()
.getOrCreate()
val conf = new SparkConf().setAppName("test").setMaster("local[*]")
val sc = new SparkContext(conf)
Instantiate the variables you are going to use :
val f_train:String = "path/to/your/train_file.csv"
val f_test:String = "path/to/your/test_file.csv"
val degree:Int = 3 // Set the degree of your choice
val maxIter:Int = 10 // Set the max number of iterations
val lambda:Double = 0.0 // Set your lambda
val alpha:Double = 0.3 // Set the learning rate
First of all, let's create first several udf-s, which will be used for the data reading and pre-processing.
The arguments' types of the udf toFeatures will be Vector followed by the type of the arguments of the features: (Double,Double,Double)
val toFeatures = udf[Vector, Double, Double, Double] {
(a,b,c) => Vectors.dense(a,b,c)
}
val encodeIntToDouble = udf[Double, Int](_.toDouble)
Now let's create a function which extracts data from CSV and creates, new features from the existing ones, using PolynomialExpansion:
def getDataPolynomial(
currentfile:String,
sc:SparkSession,
sco:SparkContext,
degree:Int
):DataFrame =
{
val df_rough:DataFrame = sc.read
.format("csv")
.option("header", "true") //first line in file has headers
.option("mode", "DROPMALFORMED")
.option("inferSchema", value=true)
.load(currentfile)
.toDF("f1", "f2", "f3", "myLabel")
// you may add or not the last line
val df:DataFrame = df_rough
.withColumn("featNormTemp", toFeatures(df_rough("f1"), df_rough("f2"), df_rough("f3")))
.withColumn("label", Tools.encodeIntToDouble(df_rough("myLabel")))
val polyExpansion = new PolynomialExpansion()
.setInputCol("featNormTemp")
.setOutputCol("polyFeatures")
.setDegree(degree)
val polyDF:DataFrame=polyExpansion.transform(df.select("featNormTemp"))
val datafixedWithFeatures:DataFrame = polyDF.withColumn("features", polyDF("polyFeatures"))
val datafixedWithFeaturesLabel = datafixedWithFeatures
.join(df,df("featNormTemp") === datafixedWithFeatures("featNormTemp"))
.select("label", "polyFeatures")
datafixedWithFeaturesLabel
}
Now, run the function both for the train and test datasets, using the chosen degree for the Polynomial expansion.
val X:DataFrame = getDataPolynomial(f_train,ss,sc,degree)
val X_test:DataFrame = getDataPolynomial(f_test,ss,sc,degree)
Run the algorithm in order to get a model of linear regression, using a pipeline :
val assembler = new VectorAssembler()
.setInputCols(Array("polyFeatures"))
.setOutputCol("features2")
val lr = new LinearRegression()
.setMaxIter(maxIter)
.setRegParam(lambda)
.setElasticNetParam(alpha)
.setFeaturesCol("features2")
.setLabelCol("label")
// Fit the model:
val pipeline:Pipeline = new Pipeline().setStages(Array(assembler,lr))
val lrModel:PipelineModel = pipeline.fit(X)
// Get prediction on the test set :
val result:DataFrame = lrModel.transform(X_test)
Finally, evaluate the result using mean squared error measure :
def leastSquaresError(result:DataFrame):Double = {
val rm:RegressionMetrics = new RegressionMetrics(
result
.select("label","prediction")
.rdd
.map(x => (x(0).asInstanceOf[Double], x(1).asInstanceOf[Double])))
Math.sqrt(rm.meanSquaredError)
}
val error:Double = leastSquaresError(result)
println("Error : "+error)
I hope this might be useful !
I've run into an issue with the TabularAdapter in the TraitsUI package...
I've been trying to figure this out on my own for much too long now, so I wanted to ask the experts here for some friendly advise :)
I'm going to add a piece of my program that illustrates my problem(s), and I'm hoping someone can look it over and say 'Ah Ha!...Here's your problem' (my fingers are crossed).
Basically, I can use the TabularAdapter to produce a table editor into an array of dtypes, and it works just fine except:
1) whenever I change the # of elements (identified as 'Number of fractures:'), the array gets resized, but the table doesn't reflect the change until after I click on one of the elements. What I'd like to happen is that the # of rows (fractures) changes after I release the # of fractures slider. Is this doable?
2) The second issue I have is that if the array gets resized before it's displayed by .configure_traits() (by the notifier when Number_of_fractures gets modified), I can shrink the size of the array, but I can't increase it over the new size.
2b) I thought I'd found a way to have the table editor display the full array even when it's increased over the 5 set in the code (just before calling .trait_configure()), but I was fooled :( I tried adding another Group() in front of the vertical_fracture_group so the table wasn't the first thing to display. This more closely emulates my entire program. When I did this, I was locked into the new smaller size of the array, and I could no longer increase its size to my maximum of 15. I'm modifying the code to reflect this issue.
Here's my sample code:
# -*- coding: utf-8 -*-
"""
This is a first shot at developing a ****** User Interface using Canopy by
Enthought. Canopy is a distribution of the Python language which has a lot of
scientific and engineering features 'built-in'.
"""
#-- Imports --------------------------------------------------------------------
from traitsui.api import TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import zeros, dtype
from traits.api import HasTraits, Range
from traitsui.api import View, Group, Item
#-- FileDialogDemo Class -------------------------------------------------------
max_cracks = 15 #maximum number of Fracs/cracks to allow
class VertFractureAdapter(TabularAdapter):
columns = [('Frac #',0), ('X Cen',1), ('Y Cen',2), ('Z Cen',3),
('Horiz',4), ('Vert',5), ('Angle',6)]
class SetupDialog ( HasTraits ):
Number_Of_Fractures = Range(1, max_cracks) # line 277
vertical_frac_dtype = dtype([('Fracture', 'int'), ('x', 'float'), ('y', 'float'),
('z', 'float'), ('Horiz Length', 'float'), ('Vert Length', 'float')
, ('z-axis Rotation, degrees', 'float')])
vertical_frac_array = zeros((max_cracks), dtype=vertical_frac_dtype)
vertical_fracture_group = Group(
Item(name = 'vertical_frac_array',
show_label = False,
editor = TabularEditor(adapter = VertFractureAdapter()),
width = 0.5,
height = 0.5,
)
)
#-- THIS is the actual 'View' that gets put on the screen
view = View(
#Note: When as this group 'displays' before the one with the Table, I'm 'locked' into my new maximum table display size of 8 (not my original/desired maximum of 15)
Group(
Item( name = 'Number_Of_Fractures'),
),
#Note: If I place this Group() first, my table is free to grow to it's maximum of 15
Group(
Item( name = 'Number_Of_Fractures'),
vertical_fracture_group,
),
width = 0.60,
height = 0.50,
title = '****** Setup',
resizable=True,
)
#-- Traits Event Handlers --------------------------------------------------
def _Number_Of_Fractures_changed(self):
""" Handles resizing arrays if/when the number of Fractures is changed"""
print "I've changed the # of Fractures to " + repr(self.Number_Of_Fractures)
#if not self.user_StartingUp:
self.vertical_frac_array.resize(self.Number_Of_Fractures, refcheck=False)
for crk in range(self.Number_Of_Fractures):
self.vertical_frac_array[crk]['Fracture'] = crk+1
self.vertical_frac_array[crk]['x'] = crk
self.vertical_frac_array[crk]['y'] = crk
self.vertical_frac_array[crk]['z'] = crk
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
fileDialog = SetupDialog()
fileDialog.configure_traits()
fileDialog.Number_Of_Fractures = 8
In my discussion with Chris below, he made some suggestions that so far haven't worked for me :( Following is my 'current' version of this test code so Chris (or anyone else who wishes to chime in) can see if I'm making some glaring error.
# -*- coding: utf-8 -*-
"""
This is a first shot at developing a ****** User Interface using Canopy by
Enthought. Canopy is a distribution of the Python language which has a lot of
scientific and engineering features 'built-in'.
"""
#-- Imports --------------------------------------------------------------------
from traitsui.api import TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import zeros, dtype
from traits.api import HasTraits, Range, Array, List
from traitsui.api import View, Group, Item
#-- FileDialogDemo Class -------------------------------------------------------
max_cracks = 15 #maximum number of Fracs/cracks to allow
class VertFractureAdapter(TabularAdapter):
columns = [('Frac #',0), ('X Cen',1), ('Y Cen',2), ('Z Cen',3),
('Horiz',4), ('Vert',5), ('Angle',6)]
even_bg_color = 0xf4f4f4 # very light gray
class SetupDialog ( HasTraits ):
Number_Of_Fractures = Range(1, max_cracks) # line 277
dummy = Range(1, max_cracks)
vertical_frac_dtype = dtype([('Fracture', 'int'), ('x', 'float'), ('y', 'float'),
('z', 'float'), ('Horiz Length', 'float'), ('Vert Length', 'float')
, ('z-axis Rotation, degrees', 'float')])
vertical_frac_array = Array(dtype=vertical_frac_dtype)
vertical_fracture_group = Group(
Item(name = 'vertical_frac_array',
show_label = False,
editor = TabularEditor(adapter = VertFractureAdapter()),
width = 0.5,
height = 0.5,
)
)
#-- THIS is the actual 'View' that gets put on the screen
view = View(
Group(
Item( name = 'dummy'),
),
Group(
Item( name = 'Number_Of_Fractures'),
vertical_fracture_group,
),
width = 0.60,
height = 0.50,
title = '****** Setup',
resizable=True,
)
#-- Traits Event Handlers --------------------------------------------------
def _Number_Of_Fractures_changed(self, old, new):
""" Handles resizing arrays if/when the number of Fractures is changed"""
print "I've changed the # of Fractures to " + repr(self.Number_Of_Fractures)
vfa = self.vertical_frac_array
vfa.resize(self.Number_Of_Fractures, refcheck=False)
for crk in range(self.Number_Of_Fractures):
vfa[crk]['Fracture'] = crk+1
vfa[crk]['x'] = crk
vfa[crk]['y'] = crk
vfa[crk]['z'] = crk
self.vertical_frac_array = vfa
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
fileDialog = SetupDialog()
# put the actual dialog up...if I put it up 'first' and then resize the array, I seem to get my full range back :)
fileDialog.configure_traits()
#fileDialog.Number_Of_Fractures = 8
There are two details of the code that are causing the problems you describe. First, vertical_frac_array is not a trait, so the tabular editor cannot monitor it for changes. Hence, the table only refreshes when you manually interact with it. Second, traits does not monitor the contents of an array for changes, but rather the identity of the array. So, resizing and assigning values into the array will not be detected.
One way to fix this is to first make vertical_frac_array and Array trait. E.g. vertical_frac_array = Array(dtype=vertical_frac_dtype). Then, inside of _Number_Of_Fractures_changed, do not resize the vertical_frac_array and modify it in-place. Instead, copy vertical_frac_array, resize it, modify the contents, and then reassign the manipulated copy back to vertical_frac_array. This way the table will see that the identity of the array has changed and will refresh the view.
Another option is to make vertical_frac_array a List instead of an Array. This avoids the copy-and-reassign trick above because traits does monitor the content of lists.
Edit
My solution is below. Instead of resizing the vertical_frac_array whenever Number_Of_Fractures changes, I instead recreate the array. I also provide a default value for vertical_frac_array via the _vertical_frac_array_default method. (I removed from unnecessary code in the view as well.)
# -*- coding: utf-8 -*-
"""
This is a first shot at developing a ****** User Interface using Canopy by
Enthought. Canopy is a distribution of the Python language which has a lot of
scientific and engineering features 'built-in'.
"""
#-- Imports --------------------------------------------------------------------
from traitsui.api import TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import dtype, zeros
from traits.api import HasTraits, Range, Array
from traitsui.api import View, Item
#-- FileDialogDemo Class -------------------------------------------------------
max_cracks = 15 #maximum number of Fracs/cracks to allow
vertical_frac_dtype = dtype([('Fracture', 'int'), ('x', 'float'), ('y', 'float'),
('z', 'float'), ('Horiz Length', 'float'), ('Vert Length', 'float')
, ('z-axis Rotation, degrees', 'float')])
class VertFractureAdapter(TabularAdapter):
columns = [('Frac #',0), ('X Cen',1), ('Y Cen',2), ('Z Cen',3),
('Horiz',4), ('Vert',5), ('Angle',6)]
class SetupDialog ( HasTraits ):
Number_Of_Fractures = Range(1, max_cracks) # line 277
vertical_frac_array = Array(dtype=vertical_frac_dtype)
view = View(
Item('Number_Of_Fractures'),
Item(
'vertical_frac_array',
show_label=False,
editor=TabularEditor(
adapter=VertFractureAdapter(),
),
width=0.5,
height=0.5,
),
width=0.60,
height=0.50,
title='****** Setup',
resizable=True,
)
#-- Traits Defaults -------------------------------------------------------
def _vertical_frac_array_default(self):
""" Creates the default value of the `vertical_frac_array`. """
return self._calculate_frac_array()
#-- Traits Event Handlers -------------------------------------------------
def _Number_Of_Fractures_changed(self):
""" Update `vertical_frac_array` when `Number_Of_Fractures` changes """
print "I've changed the # of Fractures to " + repr(self.Number_Of_Fractures)
#if not self.user_StartingUp:
self.vertical_frac_array = self._calculate_frac_array()
#-- Private Interface -----------------------------------------------------
def _calculate_frac_array(self):
arr = zeros(self.Number_Of_Fractures, dtype=vertical_frac_dtype)
for crk in range(self.Number_Of_Fractures):
arr[crk]['Fracture'] = crk+1
arr[crk]['x'] = crk
arr[crk]['y'] = crk
arr[crk]['z'] = crk
return arr
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
fileDialog = SetupDialog()
fileDialog.configure_traits()