I jumped into the water with a distribution plot and found one of my old friends, the picture control. I have used the polar plot UI control for a previous project. I remember how I had to use the “drivers”, or the SubVI library, and recreate my own SubVI’s for my particular functionality needs.
For the Makeover Monday Crowd, a SubVI is a seperate piece of code that can be reused, or called, by other code. It is not unlike a function, it can be small and have very specific and concise functionality, or a SubVI can have as much functionality that it could be like a main code piece. A VI, in general, is a piece of code that exists as it’s own file. SubVI is a term used for a VI that is smaller and specific in its functionality.
UI Functionality and Code
The UI is a straightforward picture control, listed in the pallett as a distribution Plot. It was not until I dropped it on my front panel that I realised it was a picture control with a helper SubVI.
I also used a Vertical Pointer Slide, which is a numeric front panel control, so that the used can select the data set to display. I set this control by reading out the headers and using their names to set the possible values in this control. In this way, if the data set changes, the code doesn;t have to update in order to display whatever data sets are available.
The reading of the data file uses a technique I have stuck to lately, that is to evaluate the data at the edge of the file read, and place it into a format that makes display easy. In this case I decided to to use a three dimensional array, where each page is a year of data.
This data set came up with a lot of potential. The daily ins and outs of the job precluded me pushing through the full options.
For example, a dial for each year could be added to show the respective sets of plots.
Ideally the data points with empty values should be filtered out of the data set.
The big picture would be to update the picture SubVI sets to expose all the features of the plot that we would want to have. This would include colors, plot point sizes, and most importantly, the ability to put text into the x-axis, that is, the country names.
The SubVI set, of what I like to call the driver set, only exposes a limited set of setable features. Perhaps this control was meant to be used as a probability distribution plot, in which case it would not be the best choice for this data set. I might expect there to be some additional utilities or SubVI’s to calculate probability results, but could not find any, if that was even the intention. Live and Learn.
However, the distribution plot being a picture control is a great segway into using picture controls on some of our upcoming data sets. Also a hint to myself to pick my controls to match the data. But … I am keeping with the feet first, take a week only approach to these data sets for the near future. Fun, furious, and I find it to be a good learning method.
Short code, not such a great visual. It would have taken a lot of time to properly use the picture code to display this data set in a Data World quality way. Moving on to the next data set, but keeping the picture control in my back pocket to pull out for a upcoming data set.
This weeks data set from Data.World was a nice yearly trend showing declining bike sales, a seemingly straight forward data set.
I figured I’d use a Front Panel control that I’ve never used, really, I’ve never noticed it sitting there, hiding innocuously on the graph pallet.
The idea was to have the XY Plot Matrix, lets just call it the “the graphs”, use it’s ~apparent~ functionality.
That is, to setup the data so that each automatically generated graph would be one year. Then I would loop through each graph and set all the parameters. In addition, would make some color coding of the plots to show the declining sales.
Unfortunately, the graphs is really just an X-Control.
For the Data.World crowd, an X-control is a UI element that has some programmed functionality and behaviors. In this case, the “XY plot Matrix” is supposed to build a chart for each X and Y combination of data. So in our case, I wanted there to be a set of sales for each quarter crossed with each year there is data. This would create a plot for each year, and would allow for the data set to be expanded or shrunk.
It turns out this X-control, the graphs, is not a complete product. After searching NI.com I found only six hits while searching the forums for this graph, and only one article actually about this control.
I assumed we cold step through the graphs, by using the graph position to select each graph, and then use property nodes to set the UI elements of each graph.
The X-control gives no touch points on any of the graphs, only the first graph. So it is a complete bust. Some elements apply to all the graphs, such as the X and Y axis labels. So you can’t programmatically set those per graph, so no way to indicate what year each graphs X-axis data is.
Otherwise, some of the properties only affect the first plot, so you can’t set the line thickness, et al …. , for any of the other plots.
It would be a challenge to dig into this X-control, but if I were to do that, I’d rather make my own X-control.
As was mentioned in one of the NI forum posts, it would almost be easier to just manually control a set of graphs off screen, and have them fly in as needed, and then set their individual properties.
The experience was frustrating, because the idea of Data.World is to present the story that the data tells in a compelling, visual, and intuitive way. This week I wrestled with the ‘cast off control’, and although I learned a bit, I felt like I was not able to focus on UI elements.
Ultimately I had to finish, and manually “Gussy up” the graphs for a one time screen shot, and move on to next weeks data set.
This week I focused on using an intensity chart, which I have not used previously. It is an interesting way to display data, not sure if I am a big fan or not. I like that it can show three sets of data, but it was not as friendly as I thought t would be. I look forward to using one again in another Makeover Monday.
In this weeks UI there are no action buttons for the user. I wanted to put in a dial that would allow the user to select the data column from the data set, to display on the Z axis. This would require repopulating the XY array with the new data, and re-sorting the data.
The data set has the rank of the state the same as the “equivalent homes powered”. So changing the Z-data would really show contrasts with the rank (equivalent homes powered)
There are some “off screen” controls that allow the developer to update the levels of the intensity markers.
For the Data.world crowd, the intensity markers are the values in the intensities (Z axis) and the colors associated with those values. I have set the graph to interpolate the colors along the z-axis, so these markers allow a developer to redraw the graph intensities in order to make trends stick out.
This graph, like the article ( https://howmuch.net/articles/wind-power-in-the-united-states-2018 ), shows that the equivalent homes powered doesn’t track exactly with the installed capacity. On this graph the bars (capacity) are not in order but the intensities (houses powered) are.
I should have changed the Y-axis labels to display the investment values instead of just the rank. LabVIEW doesn’t seem to have a good way to make multiple axis labels, in order to be able to show values and text together. I’ll have to check to see if this can be done using ‘regular expressions’
Similar to last weeks data , I found the range of the data, in this case the equivalent homes powered, to be so large that it was hard to showcase the lower values when the highest value was orders of magnitude greater.
I spent a lot of time getting used to the intensity chart. There is a ‘developers version’ of the main code. It has a lot of ‘switches’ in the code to play around with. The final version has a clean block diagram.
For the Data.World folks, the block diagram is the code, it is where the graphical program is drawn.
I used a While loop to keep the chart active, so the developer can update the markes list and its colors.
After reviewing this all I can say I am looking forward to my next intensity chart, so I can focus on the data and telling the story.
Also thinking about using a 3D graph, I haven’t used one in quite a while.
Executive time, leaked to the press, not such a great data set, but a good set of data for my seventh Makeover Monday. The single value is a huge outlier, if it were my data set I would have the team come up with a better set of metrics.
I thought about adding up like times, into meta groups, like meetings, lunch, rallies, etc … But one look at the data and the only lesson to be drawn is that executive time is the largest, by far.
UI Functionality and Design
This week I used a simple XY graph, with a lot for each data point. One could have put the data as a line and use the fill type lot, but I prefer the control of using each data point as a two point line starting at the zero position.
I need to find a better way to put names in the axis instead of numbers in graphs and charts.
Code and Article
Not a lot of frills on this one, sticking with a straight forward display of the data set. The subject matter did not have a lot of ins and outs to explore. On to the next week, number eight.
Crazy busy travel schedule. Comparing three metrics for consumer behaviour during respective national holidays.
For the data.world and makeover monday folks, a ‘snippet’ is a png picture of your code, that contains the code, and can be dropped in the program environment (IDE) and puts the code into your current program. Kind of a cut and paste of code.
I was inspired by the original graphics, https://www.statista.com/chart/3246/how-chinese-new-year-compares-with-thanksgiving/
so I was looking for a control that might have a round look to it. My first thought was to used meter controls , and so I stuck with that approach.
I replaced the pointer and center pivot with images to match the holidays. It retrospect, I should have looked to see if the meter display could be stretched into more of a complete circle rather than just a limited arc.
Because of the numbers involved, I choose to display two of the meters in logarithmic scale. I’m not sure if the average person reading an article would comfortable visualize the scales involved this way. However, the dial seemed very limited in its ability to display a nice, wide range of values, so in two cases, te display of one of the meters appeared to be zero.
In addition, I added a switch, to scale the values by the number of 1 million peoples in the samples, a sort of per capita of 1 million people. I didn’t see a large change in what was displayed, indicating that in both absolute dollars and in per capita, the relative differences between the two countries was the same. This was all based on how the graphs looked, so maybe quantitative measures could have told that story, but talk about scope creep.
I didn’t think about the actual differences in sheer values, and how these would affect the meter control’s display. So part of the lesson is to cleanse and evaluate the data prior to designing the display. However, the spirit of these lessons that I am using is to jump in head first, rather than treat the effort as a paid gig.
This affected me because the way the meters were displaying the data, the low values looking like zeroes, I spent some cycles troubleshooting the code.
I even went through the effort of programatically scaling the meters with high and low values. Turns out the low values still displayed in a way to look close to zero even though they were large numbers, but small numbers compared to the max. Thus the Logarithm ended up being a programmer’s choice, but maybe not a best “viewers choice”
This ended up being a simple read, analyze, and display. I used an event structure that only looks for the switch change. So, possibly overkill, but I think I am going to keep this approach, rather than polling, even on simple displays. I also made a snippet for the simple “empty” event structure.
I left the programmatic updates of the meter min/max values sitting like an bump on a log in the code. In retrospect, I would have evaluated the data challenges, and created the min/max values in the data read step, and passed them on in cluster to be used in the programmatic update of the meters.
Time to run on to next week and catch up. Meters are fun, but I need to explore updating the display to stretch further. With time I would have updated the switch to have a different visual element than a switch push button.
LabView shows it’s quirk in importing a field in quotes that has commas in it. It doesn’t recognize the quotes, and treats each commas as part of a CSV. Maybe there is an openG file loader that sees these like SQL does.
This week I got stuck on business travel for five days, so I got a late start on the Data.World data set. I cut off on Tuesday, giving myself two extra days.
I wanted to use a knob and a XY graph. The data set is challenging because there are five “dimensions”, or metrics, per country, and five years of data.
My thought was to have a knob to display the year of choice, in order of largest composite score. Then have a second knob to set the order of the largest value of a selected indicator score, including the composite score. I ran out of time on the second knob. Details on how this would be implemented is below.
I set the knob to show the year instead of a standard number. This is all native functionality.
The data is in text and numbers. I started out by focusing on the numeric values, not realizing that I would have to account of keeping track of the country name.
In addition, I have to calculate the composite score, and store it by country and year too.
I ended up using clusters to hold the data that I wanted to display or manipulate. This is much easier than running parallel arrays, for numeric values and for text values.
For the Data.World crowd, Clusters are like containers, they can hold all sorts of data types, text, numerics, arrays and more.
There is a file I/O function. In it I also perform some small calculations to provide meta data later on. As an Aside, I think I will start creating more meta data functionality blocks. I noticed this is becoming more and more needed as I progress through these exercises.
After I/O the data is manipulated to create the composite score, and then to sort by that value, for each year. To do this you also have to keep track of what number goes with what country, this is where clusters come in handy.
The next step is to prepare the graph. For this data set, I had to create a plot for each indicator of each county, for each year. So, having the value of each indicator is not enough, I had to create the points that are the stacking of the individual indicators on top of each other, in size.
Once the graph and data are ready I set up a loop so that when the knob changes, the graph is updated with the data from the respective year. I calculated the yearly data sets, and stored them in an array by year. This way we are calculating the data organization once, only having to display it thereafter.
The second knob I didn’t get to would have been selecting the indicator value, including the composite score, and having the graph order the data by that value. Currently it only sorts by composite score. To do this, it would have been the same exercise, that is, create all those plots, and then store them. I would have used a 3D array, where the pages were years, and the rows would have been the indicators.
The article & Code
I hope you enjoy the code. There was some hard coded elements due to time restrictions. I’m looking forward to starting to customize the native UI elements. Time permitting I should start to get these worked into the weekly routine.
10 Downing Street energy usage, the new data set for Makeover Monday. For this week I decided to use a waveform graph.
For the Data.World crowd, a waveform graph in LabVIEW will take and display a data type called a waveform. This data type, a container of sorts, contains a starting date/time, the time interval between points, and an array of data points.
Although I have usually used the waveform for scientific data, it seems like a good fit for data set that is based on a calendar.
The graph comes standard with it’s organic graph controls. Mainly types of zooms. I wanted to add in the ability to translate or zoom using the mouse.
When the mouse pointer is hovering over either of the values of the graph axis the mouse can then control the graph view by the use of the wheel. Scrolling the mouse will move the data to the right or left, translated. If the right mouse button is held and the scroll wheel is moved, the graph will zoom in or zoom out at that point.
I noticed the data is provided missing the first energy value, and also sorted alpha numerically in the half hour column a second level sort after the calendar day sort , so that in any day, the half hours are not in order. They go .5, 1, 1.5, 10, 10.5, 11 ….. 2, 2.5, 20, 20.5 , …… So they have to be sorted. I decided to just fill in the one missing energy, rather than go through all the hoops of data validation, where I would discover missing data an most likely put in an interpolated value or discardit as bad data.
There is a lot of effort required to know where the mouse is in relation to the graph axis values. All of this is made more interesting based on where the graph is in relation to the origin of the front panel.
My effort to implement the zoom feature of the mouse involved determining the two distances from the mouse to the ends of the axis location, i.e. the top and bottom of the vertical (y) and the left and right fo the horizontal (x). I got it mostly correct, but I seemed to have missed a subtlety. The graphs also translate a bit while they zoom. It is much more evident in the x-axis, the calendar date/time. I think it is more evident as this value is stored as the number of seconds since 1900.
I’ll have to come back at some point a figure it out.
This weeks UI was a single element. I focused on the mouse zoom and translation. I probably should have spent more time with pen and paper to really map it out, mental note to self. But .. having gone with the more relaxed approach, I ended up using more troubleshooting efforts, tracking values in the code using probes.
I wanted to make the x-axis, the time, to be more like the original chart from data.world. It was my plan to make the zooming go from one year, to zoom to one quarter, to zoom to one month, and then to one week. So it would not be an analog zoom, like the Y-axis, but more of a discrete steps zoom.
Minimum wage, my second Data.World entry. I completely ran out of time on this week.
My first several data sets I am going to continue with the theme of using the native LabVIEW FP controls.
This week a slider and a tree are making an appearance. I set the slider to use actual numbers as the scales.
For those from Data.World a few LabVIEW pointers. Talking about the wires, is a reference to the code. LabVIEW is a visual data language, and the data flows along wires. The code looks like a circuit, to a certain extent, so thus the name wires for the data flow. The “pallet” refers to a small pop up window that shows all the functions that can be used in LabVIEW. So if you want to use a function that adds two numbers, the add function is on the pallet.
Click on the slider, to select a year, and the data for that year will display in the tree. Very simple.
I should have put the headers into the Tree so a person would know what the heck they are looking at. Well, I’m holding myself to a one week cut off. Also, I needed to put some cleaner looks on the slider and the Tree, they are really almost straight off the pallet.
Main Process and Development
I got caught up in the process of massaging the data. I developed an idea to use a three dimensional array, where each page was all the data for one state.
In this way, I could easily go to each page and pick out the year data.
The main loop uses a case structure to act on the change of the slider. When there is a change, the year selected is used to search each page.
For the code, I decided to force the code to have to look up all the sizes and ranges, and set the slider values. This way, if next year (week, etc…) we get a different data set, the slider will set itself to the range of years in the data, the number of stated, the number of columns, etc…. as much as possible.
I had to cut myself short, so the Tree Bins I hard coded from the article.
I can see how these data sets give a person a lot of choices on how to code, how much to focus on the wires and how much on the display. For this one I took to much of my limited time on the code, as opposed to the display.
For example, I decided to make two large arrays of the file data, one as text, the other as numeric data types, this way I didn’t have to continuously update the data type for display and use later on. However, since I stopped developing functionality, I ended up not using the numeric data type for calculations … I had been thinking about coding colors for states above or below the national average, or to also make a display of each states rate of change of their minimum wage data.
I did use the numeric data to bin the states, by comparing the state values against the bin values, for sorting the states into bins in the tree.
Source Forge: 1-14-2019 minimum wage folder –> https://sourceforge.net/projects/data-world-labview/files/1-14-2019%20Minimum%20Wage/
I could put in another week on this, but gonna keep as is to stick with a one week timeline. First view of the slider and the tree. Spent a lot of time messing around with formatting the data. I wanted to preallocate all the arrays, even though this data set is small, I want to keep with the approach that I would use for large data sets, that is to reduce memory allocations and data copies.
Freedom of the press. My first run at the Data.World data set. I decided to use multicolumn tables, combo boxes, and XY Graphs. For the UI, I am sticking with the organic front panel controls, but colored to a very plain white look.
For those from Data.World a few LabVIEW pointers. A VI is a like a subroutine or a function. The Front Panel (FP) is what you see, and the Block Diagram is where the code is written.
My intent is to get up to speed at quickly making updates to standard User Interface elements. My first few projects will likely be me refreshing on some of the finer points of the UI elements, so there will be a lot of standard “looks” for a while.
The main UI functionality will be to display a selected plot in one graph. I also wanted to be able to stack multiple plots, so I use a second graph to “stack” multiple plots for comparison. However, I use a switch to activate the addition of plots to the “stacking graph”. Finally I want to be able to remove plots from the “stacking graph”.
I wanted the user to be able to use the drop down feature of the combo boxes to select plots to show or add, and to select plots to remove from the stacked graph.
The three actions are 1) displaying or adding graphs from the full list combo box. 2) Removing plots using the ‘remove’ combo box. And 3) using the switch to turn on or off the the functionality for adding plots to the stacked graph.
The Multicolumn tables require deliberate clearing, they can’t be simply reset with an “init all to default” command. I also set the active cell to the 0,0 point.
Generally each of the controls has to be set clear, and a lot of it can be done using the VI level ‘re-init to default values’ function. However, the combo box and the multicolumn list box are set to clear using their property nodes.
Graph inits are always intensive, having to clear the plot data and the plot names. In more complex plots, you might also set colors, line size, cursors, etc… So for this I made a subVI for all the actions needed. For this UI it was only plot names.
I created a subVI to read in the data, and then to arrange it into the format I felt would be the easiest to use for placing the data into the UI elements.
I decided to use a polling loop to look at changes in the combo boxes. These two changes would indicate that a new plot is to be displayed/added or that a plot is to be removed from the stacked plot.
During the update, if a new plot is selected, the switch is also checked to see if the country should also be added to the stacked plot. If the “county to remove” combo box is changed, then that country is removed : the plot, plot name, and the county name from the combo box.
The User Interface
Data world is all about displaying data. For this project I am displaying data using native controls. I was running short on time, so they are not as dynamic as the could be. To make them resizable, panels could have been used on the front panel.
The list boxes contain all the entries for each county year and year data.
I would probably change the graph background color too. A mental reminder to focus more on the UI than the code. Ha Ha, but I honestly ran out of time, I am making a point of cutting myself off by the end of the week.
I decided to do this all without a specification document. I paid the price, as I started with a simple polling loop, and then I wanted to add the functionality of plotting multiple countries, and realized that after I finished the VI, It was easier to make a second VI, more thought through, with the full functionality I wanted planned from the start, so that is why there is a “second try” VI file.
As this is more for my personal interests, I am using a ‘head first dive’ approach to planning. I find it to be a good gut check, and a way to get more lessons learned.
So far, the major functional sections each week will likely be: clear UI elements, read file data, format data to fit the functional and display plan, and then main processing implementation.
Also, for the first several I plan to force myself into using many different UI elements for the practice, and then make the UI look as intuitive as possible for the chosen elements.
I hope you all enjoy. More details to follow. I can see adding in data output functionalities. If I can get an intuitive functionality, and display the data as desired, it would be great to add the output, either files, reports, or both, that are based on how the user chooses to display, and what subset of the data they choose.