Jumat, 10 Agustus 2012

I haven't blogged here in a while because I'm not working directly for  dashboard company anymore and I'm in the process of moving to a personal blog, but since I still have this site, I thought I'd mention a cool product I saw a demo of tonight.  It's called Dash from Five Runs in Austin.  Out of the box, it's a really nice tool for instrumenting your Ruby on Rails applications but they've made it extensible and language-agnostic so that other languages can work seamlessly.  Even more, they plan to allow you to use their product as a source to store metrics so you can access them and display them any way you want.  For example, you could upload supply chain events (order received, order shipped, etc) and use their tool to overlay graphs to show differences between DCs or correlations that might help with analyzing problems.

They're in private beta right now, but check out their site and request a beta key if you're interested.

Wednesday, July 9, 2008

Relationship Analysis/Visualization

I recently had the need to evaluate a few different social analysis tools for a project. These are tools that visually show relationships between entities. For example, it could show a representation of your friends/connections on Facebook or Linked In. Then you click on a friend and it shows their network and so on. I looked at open source library called JUNG (Java Universal Network/Graph framework) which was pretty nice. There were a few other commercial offerings that looked ok.

But the one that really caught my eye was the BirdEye Relationship Analysis (RaVis). It's written in Flex and it's just flat out cool. It actually made me spend time to think of possible ways to use relationship analysis in applications that really don't need it, just so I could use the tool.

Check out the demo here. Here's the home page for the suite of related tools.

Thursday, June 26, 2008

Every App is a Dashboard

I just realized today that I can barely design an application without turning it into a dashboard. I'm really trying specifically not to build another dashboard application, but whenever I step back, it looks suspiciously similar to other dashboards I've built.

Web applications generally consist of task-oriented pages and reports. In my domain (primarily enterprise supply chain), many of the tasks are done by hand-held devices of some kind. That leaves a handful of data entry screens and the reports. Greenbar is probably not the way to go these days so the reports are going to be online. Displaying HTML tables with thousands of rows is not all that useful so we need to summarize, highlight, and allow drilldowns to details. Hmm... that sounds familiar.

I'm not saying this is a bad thing, it's just kind of amusing. The challenge is to really think about the layout so that it provides the most value to the user, without getting trapped into assuming a grid of gauges/widgets is the way to go.

Sunday, June 8, 2008

Semantic Web

I recently read an article about the semantic web. Like search, the semantic web is a powerful way for a person or organization to extract information from data. The idea (over-simplified, if not half wrong) is that a group of experts in a domain can define a way of representing data for that domain. Applications or people that generate data for that domain do so in the official format which allows computers to use that data to make inferences, i.e. "learn".

The semantic web could potentially provide even more power than search for corporations trying to optimize their business. It's a little fuzzy like search in that there is not necessarily a clear path to the one true answer. On the one hand, how do you sell someone on a dashboard that may or may not return a useful answer? But on the other hand, why shouldn't corporate dashboard users have access to tools that are powerful enough to answer questions the user hasn't even thought of yet.

At a minimum I think ideas from the semantic web can be leveraged for business intelligence analytics and could make it much easier in the future to write applications that integrate with multiple different data sources.

Friday, May 30, 2008

Dashboard SDK

As I mentioned in a previous post, my company has added a new software development kit to our dashboard application. I was recently asked to prepare a demo of a gauge for a potential customer. The idea is to show information about a set of inventory picks within a warehouse including total travel distance, and the density of products and locations. The customer can use this to measure how efficient their picking process is.

I've been using Ruby more and more recently so I decided to actually create a first cut of the gauge using our Ruby in our SDK. A screen shot is below, followed by the actual code (disclaimer: I'm fairly new to Ruby and I was purposely verbose to illustrate the details; this could have been done in Groovy, Java, or JavaScript as well). The point is, I seriously doubt a report like this could be easily built using a drag and drop BI tool. The code required some specific knowledge of the data structure, but anyone creating something like this will need that domain knowledge anyway. This only took a few hours and it fully integrates with the framework meaning it can be configured per user, output to Excel or PDF, set up as an Alert, etc.

So more evidence for my earlier assertion that business intelligence requires code.



Code (note: this is running inside a Java framework via JRuby so is accessing the database through Hibernate):
include Java
import 'java.util.ArrayList'
import 'WaveSummary'

# Get the list of Ickpts (inventory runs) either from the parameter ($ickpt)
# or the database if they want all

where = 'where 1 = 1 '
if ($ickpt and $ickpt.length > 0) then
 where += 'and ckpt_id in ('
 $ickpt.each do |i|
   where += i.getName() + ','
 end
 where.chop! # lose the last comma
 where += ') '
else
 # No parameter value; get them all; we could filter by date but some span days
 ickpts = $session.createQuery("from Ickpt").list().toArray()
end

# Build map for easier lookup of ickpt record later
ickptMap = Hash.new
ickpts.each do |i|
 ickptMap[i.getIckptKey().getCkptId()] = i
end

if ($dateRange != nil) then
 where += ' and create_dtim between :from and :to '
end

# First query to get the unique slots
query = $session.createSQLQuery("select ckpt_id, count(distinct sel_loc) from aseld " + where + " group by ckpt_id")
if ($dateRange) then
 query.setDate("from", $dateRange.getDateRange($timeZone).getFrom().getTime())
 query.setDate("to", $dateRange.getDateRange($timeZone).getTo().getTime())
end

summaryMap = Hash.new
query.list().each do |result|
 s = WaveSummary.new
 summaryMap[result[0]] = s
 s.uniqueSlots = result[1]
end

# Next, get the unique skus
query = $session.createSQLQuery("select ckpt_id, count(distinct prod_id) from aseld " + where + " group by ckpt_id")
if ($dateRange) then
 query.setDate("from", $dateRange.getDateRange($timeZone).getFrom().getTime())
 query.setDate("to", $dateRange.getDateRange($timeZone).getTo().getTime())
end

query.list().each do |result|
 s = summaryMap[result[0]]
 if ! s then
   s = WaveSummary.new
   summaryMap[result[0]] = s
 end
 s.uniqueSkus = result[1]
end

# Now query to loop through the picks to calculate the distance
query = $session.createSQLQuery("select ckpt_id, sel_x_coord, sel_y_coord, assg_id from aseld " + where + " order by ckpt_id, sort_seq, sel_loc")
if ($dateRange) then
 query.setDate("from", $dateRange.getDateRange($timeZone).getFrom().getTime())
 query.setDate("to", $dateRange.getDateRange($timeZone).getTo().getTime())
end

lastX = lastY = lastCkpt = lastAssg = 0
query.list().each do |result|
 ckpt = result[0]
 s = summaryMap[ckpt]
 if s == nil then
   s = WaveSummary.new
 summaryMap[result[0]] = s
end
assg = result[3]
if (lastCkpt == 0 or lastCkpt != ckpt) then
lastX = lastY = 0
end

x,y = result[1],result[2]
if lastAssg != 0 and lastAssg == assg then
 if lastX != 0 and lastY != 0 then
   s.distance = 0 if ! s.distance
   # Just using straight-line distance between each sel loc
   # This is not exact, but close enough for comparison
   s.distance += Math.sqrt((x-lastX)**2 + (y-lastY)**2)
 end
end
lastCkpt, lastAssg = ckpt, assg
lastX, lastY = x, y
end

# Dump the map into a list to return
data = ArrayList.new
 summaryMap.each do |ckptId, s|
 s.ickpt = ickptMap[ckptId]
 s.distance = 0 if ! s.distance
 s.uniqueSlots = 0 if ! s.uniqueSlots
 s.uniqueSkus = 0 if ! s.uniqueSkus
 s.distance = s.distance/12 if s.distance > 0
 s.slotDensity = s.distance/s.uniqueSlots if s.uniqueSlots > 0
 s.skuDensity = s.distance/s.uniqueSkus if s.uniqueSkus > 0
 data.add(s)
end

data
belajar ngeblog