shoes / shoes3

a tiny graphical app kit for ruby
http://walkabout.mvmanila.com
Other
181 stars 19 forks source link

Radar/Spider/Net Charts #288

Closed ccoupe closed 7 years ago

ccoupe commented 8 years ago

Here's the latest view on radar charts. Just draws the radial axes and the label of max value of that column. It draws the label poorly but we talk about 'better' after the image. radar-2

In gruft and other source code I've looked at, our chart_series is equivalent to a row and the value inside the rows are columns. Radar and the like, like to draw/compute down columns. Shoes currently has no API to specify some things for that orientation that users might find useful. In the example above, the labels shown are the computed max (down the columns) but before we can scale and and draw some data points and connected lines, they need to be scaled between min and max. What's the value at the center for each? Compute min? 0? Something else? Can it be specified by the user and if so, how?

ccoupe commented 8 years ago

Sadly, we do need add an extra arg to plot creation when creating a radar. The most natural is an array of arrays. Ick! Do I have good name - of course not! Let's call it "column_settings:" until someone suggests a better name and it only applies to certain chart types and it is mandatory for radar (and perhaps some new chart types in the future).

plot {...., chart: "radar", column_settings: [ <column 0 settings>, <column 1 settings>, ...]} What's in a 'column setting'? I think it should be another array or a hash - users choice. Hash is more descriptive but it gets wordy so both should be acceptable { label: <string>, min: <number>, max: <number>, format: <printf_format_string> } .You might wonder about the format: string. If not given then it defaults to "%4.2f" which is not optimal for anyone who cares about their graph. I could even imagine other options like alpha: 0.5 if you want the damn things dimmer (I would).

seeking opinions @BackOrder , @passenger94 .

IanTrudel commented 8 years ago

What this new parameters for? It is normally possible to create radar graph with same kind of plot data as any other graphs. For example, see this tutorial for Microsoft Office.

Now it might be a good idea to support optional parameters for plot. I'm just confused why it would be mandatory for radar graph...

IanTrudel commented 8 years ago

Also as reference another tutorial.

ccoupe commented 8 years ago

Excel and the like have the labels for rows and columns (because they have to be there, or you have to add them later in the wizard) Shoes does not have a wizard for creating charts. Suppose the two values in column 0 are [80, 180]. Are those 0 based? Or should that 80 be the dot in the center? What if another radial/column on the same chart ranges from 20 to -10. Since Shoes adds and draws (chart_series) row by row and does not know how many rows will be added later. It draws what it has and for radar/spider it needs to know the min/max of the radial axis to draw. Review some of those example you posted on the old thread and your see some very "unigue" things about the labels/xaxis/radials.

IanTrudel commented 8 years ago

My understanding is that radar graph is based on its given values, using minimum and maximum values and evenly stepped. Minimum value is the centre. We may offer optional parameters (unit, scale, step, etc.) for customization. Does it make sense to you?

ccoupe commented 8 years ago

It make sense in some cases. And lacking for others. In the [80, 180] case, you only get two dots when it gets around to drawing the lines and dots - center and the outer radius. What to do if you know that 180 is not the max score on the test and 80 isn't the worst. Maybe 250 is the best (outer ting and 50 is the worst (center) . How to specify that?

IanTrudel commented 8 years ago

Would you mind sharing a sample code of radar graph in Gruff or any other related API (slash language)? Maybe we could learn something from it.

ccoupe commented 8 years ago

Crux => matter. Excel is an interactive tool for creating charts. Shoes is declarative. So is gruff (clone it and look at the test cases) or pycha and look at the test cases (hard to find). Look at what gnuplot uses for a DSL (bonus points if if you can find a radar/net/spider example that makes sense). Matlib? Wolfram? Some Adobe Thing?. Shoes can't be all of the above. Use them if Shoes is too much trouble.

IanTrudel commented 8 years ago

Take a look at Chart.js and rgraph. They both have a very clean API. Please, notice Chart.js has an options argument for the special case(s) you are referring to. Otherwise, they both proceed as I stated before.

ccoupe commented 8 years ago

There's no doubt that my bottoms up approach is problematic. Originally, all I wanted was the timeseries chart that I could append RT data to and add and delete series. And then it grew from there. It's not a goal for Shoes to replace dedicated charting applications (or spreadsheets). Just something simple. Now, it's not so simple.

I'm considering (just thinking aloud) that the existing Time series chart and RT stuff should be a different widget (and api) from all the other charts or perhaps an alternative api for all the other other chart types. For now, I'll probably bumble ahead just to finish up and learn some things.

IanTrudel commented 8 years ago

It would ideally be implemented in Ruby/Shoes level for maximum extensibility but this approach has its challenges.

Regardless of the current flaws or original intents, I assure you this is a very desirable feature. Charting feature is surpringly difficult to find in any language.

ccoupe commented 8 years ago

It would ideally be implemented in Ruby/Shoes level for maximum extensibility but this approach has its challenges.

266 + gruff for a template. Maybe we can talk @passenger94 into implementing the text_shape.He know more about that place inside Shoe than I.

Regardless of the current flaws or original intents, I assure you this is a very desirable feature. Charting feature is surpringly difficult to find in any language.

I also observed that empty spot in the OSS desktop universe. It's why I'd like to get this feature 'good enough' for fun and exploration without getting too complex or detailed.

  @values1 = [80,        160,          145,     75,          80] # in k$
  @values2 = [180,        90,           95,     90,          90]
  @columns = [ ["Internet", 0, 250, "%4.0f k"], 
               ["Television", 0, 200],
               {label: "Radio", min: 0, max: 200, format: "%3.3f"},
               #["radio", 0, 200],
               ["Newspaper", 0, 200],
               ["Magazine", 0, 200]
             ]

...
       @grf = plot widget_width, widget_height, title: "Advertising", caption: 
          "Budget Spend" , font: "Helvetica", auto_grid: true,
          default: "skip", background: white, chart: "radar", column_settings: @columns
      end

Not completely awful. Extensible at the C level (sort of).

[updated sample on 2016-11-05]

ccoupe commented 8 years ago

Getting closer. radar-3

There are many things to improve but basics are not awful.

IanTrudel commented 8 years ago

Looking good!

ccoupe commented 8 years ago

Slightly more appealing. Incorrect label positions but improving. radar-4

IanTrudel commented 8 years ago

Are measurement lines also implemented? It seems to go really well so far.

Good news is that features you have implemented lately, radar graph included, will allow me to port one of my prototypes on Shoes and implement a fully functional prototype. Thanks for your continuous efforts!

ccoupe commented 8 years ago

Many, many and more details need to be added. I assume measurement lines are the lines drawn round the axis connecting the xaxis labels. In the tiny chart above there is room for an outer ring connecting all 200 end points and say one 'ring' at 100' since the examples all start with 0 at the center point.

Remember, all five of the above axis can have different scales so you need value labels on each of those points which can make for a very busy chart. And of course, someone will want options to not do that or only draw two when the room for 10. Or maybe they just want little 'tick' marks instead of labels. Another API challenge! There really is no end to possible enhancements and feature creep to this and many others charts all of which are very difficult to (re)implement incrementally in C. (wouldn't be that much easier in Ruby)

If you can provide a screen shot of what you really need (and the test date), that would help.

IanTrudel commented 8 years ago

Statistics Feature for Humintell Products is how I use radar chart in general. This is how OpenOffice/LibreOffice generate basic radar charts.

You may notice the scale is in percent from 0% (center of the chart) to 100% (outward). The scale is the same for every item (7 universal emotions in this case). Each coloured line represent percentage obtained at a precise moment in time (pre-test score, practice score, post-test score). In this document, the pre-test never change once taken, practice is updated as practice goes, post-test is created once post-test in taken (and possibly updated if taken again).

In a nutshell, basic features are fully sufficient for most case scenarios. The extra features you are suggested are fine but as long as the basic ones are fully implemented, I can use your radar graphs.

Let me check if I could get some data for you... stay tunes.

IanTrudel commented 8 years ago

image

ccoupe commented 8 years ago

Thanks. I'll use that for a for another test case (gr7.rb). We can get pretty close today. South of your border, an number of people appear to need help handling their emotions after the recent election.

ccoupe commented 8 years ago

I do like other peoples tests. This one demonstrates just how much work remains. radar-5

There is a Windows beta that (hopefully) can draw that if you get the Tests/plot/gr7.rb from github.

IanTrudel commented 8 years ago

Indeed, indeed. The data in your recent commit seems to be on point with my table. Unfortunately, the radar graph is incorrect. It seems some data is mixed up internally. Also, notice my example starts with Anger on top as it is the first item.

image

ccoupe commented 8 years ago

There are many bugs on the to do list. That's one of them.

ccoupe commented 8 years ago

Also note that Shoes and Your example are the difference between clockwise and anti-clockwise. Either way will convey the same knowledge, right? (another reason I don't love radar/spider)

IanTrudel commented 8 years ago

The main objection is that every other engine, API and office/drawing suites is drawing radar graph the same way. It means anyone who used it before will complain and likely to shuffle their own data (at great inconvenience) to get same result as others.

Basically, might as well do the same.

ccoupe commented 8 years ago

Back in the days when I managed Software Engineers, They would have said the same thing when I proposed a different way forward. Convention is paramount! They would push back and sometimes they were correct and sometimes they pushed back, just because it wasn't done their way . Now, I'm just a SE of dubious skills on a collaborative OSS project and sometimes I'm the self appointed manager of this "new way to write Ruby GUI's that doesn't it do the conventional way".

IanTrudel commented 8 years ago

Haha! You know I earn a living doing different way from others? It however has to make sense, has a rationale behind the change.

So what does your current implementation bring that the conventional way doesn't?

ccoupe commented 8 years ago

So what does your current implementation bring that the conventional way doesn't?

We've gone through this before. Real Time updating (timeseries charts), add and delete series of data from displayed charts (varies by chart type), very large data sets that would take weeks or months to type by hand and mostly, 2800 lines of C code and partially finished documentation and many man hours that are not amenable to 'just redo it this way'.

Once we get #266 implemented then anybody else can write many many lines of Ruby/Shoes that does it 'their' way for their api and it won't interfere with the minimalistic C plot widget.

IanTrudel commented 8 years ago

Well, doesn't the radar graph just need rotation? Shouldn't be a big deal..

ccoupe commented 8 years ago

Depends on the C code whether it is a big deal or not. I'd like to have the outer labels rotate in the same direction (known bug) before I care about which direction they rotate. It makes no difference in user comprehension of what is displayed. You don't have to look very hard to find that is there is no convention for your chosen direction. Useless Quibbblles.

ccoupe commented 8 years ago

Some success with measurement lines ( I call them rings in the C code) These examples draw 3 rings. Notice how Shoes detects that there may be different scales needed. radar-6 radar-7

Yes outer labels are wrong.

IanTrudel commented 8 years ago

It's enjoyable to see the progress. Please, notice the lines from center to outwards are progressively lighter. I suspect each section are redrawn on top of previous sections instead of just once.

ccoupe commented 8 years ago

Good eye! Thanks. I was using black+alpha because it was too hard to look up the color of gray I wanted. Another example of why more eyes than mine are good.

ccoupe commented 8 years ago

Turns out to be more that an alpha misuse. Fixed. I added an option to the plot creation api , rings: which accepts Ruby true, false, or an integer. T/F maps to 0 or 1 as you might expect. false or 0 means no radials or interior labels. true or 1 (the default) means to use Shoes' idea of how many measurement rings should be drawn for the size of of the chart. >= 2 or greater than 2 means that's how many rings you want. A bit odd, but it does make sense.

If you don't like rings: argument name, It's easy to change.

IanTrudel commented 8 years ago

Ruby true, false, or an integer.

It should be possible to support true/false without having them meaning 0 or 1. Then the integer would actually be meaningful. Also, it would allow to actually use 0 or 1 as number of rings.

If you don't like rings: argument name, It's easy to change.

The correct term is grid lines.

ccoupe commented 8 years ago

It should be possible to support true/false without having them meaning 0 or 1. Then the integer would actually be meaningful. Also, it would allow to actually use 0 or 1 as number of rings.

It checks for false or true. if neither it checks for integer. internally it's an stored in one C int, no matter what was used in Shoes/Ruby.

grid_lines is fine with me.

IanTrudel commented 8 years ago

It checks for false or true. if neither it checks for integer. internally it's an stored in one C int, no matter what was used in Shoes/Ruby.

I was under the impression it was possible to check for True or False class, as it would in Ruby.

grid_lines is fine with me.

Sure, let's go with grid_lines. It should be alright as most people will never use it, if the default value is reasonable. Ruby traditionally favours underscore method names instead of camel case. Also, lines would be shorter, shorter is normally better, but it seems too broad of a meaning to use it here.

ccoupe commented 8 years ago

It is possible to check for class names but its more wordy (plus a function call) compared to checking if its Qfalse or Qtrue C constants.

IanTrudel commented 8 years ago

It is possible to check for class names but its more wordy (plus a function call) compared to checking if its Qfalse or Qtrue C constants.

It's not really worth all the troubles, isn't it? So your way is the way.

ccoupe commented 8 years ago

Getting Closer on the outer labels and same rotation. Obvious problems - not so obvious how to fix. radar-8

IanTrudel commented 8 years ago

Here is some pointers for a proper label alignment. I drew an imaginary circle and guide lines that would be bigger than the radar graph. The point between a line and the circle is the anchor. The anchor should be use to center text on. Hope this helps.

image

IanTrudel commented 8 years ago

The following one use the same principle but the anchor is used as a left/right alignment rather than centering, depending on which side of the graph the text is on. It is right alignment for those on the left sided quadrants and left alignment for those on the right sided quadrants.

image

IanTrudel commented 8 years ago

Here is another alignment you might be interested in. Hopefully it inspires you.

image

ccoupe commented 8 years ago

Currently, you last example is close to what I'm attempting. I'm using the quad calculations from the pie chart where things look ok. One issue is that the first, top most Anger is quad 0, as is Contempt but they connect to the imaginary text box in different locations. I can special case that.

ccoupe commented 8 years ago

This one looks good enough (for Shoes) radar-9

There are issues exposed with Test/lplot/gr6.rb which needs some quadrant hints for positioning inner labels.

ccoupe commented 8 years ago

Tests/plot/gr6 requires multiple inner labels at the because not all things are scaled the the same. This is damn close to as much as I'm willing to do for Shoes 3.3.2 release. radar-10

IanTrudel commented 8 years ago

Very good! Take note the space between anger and the radar graph vs space between joy/fear and the radar graph seems different on Test/lplot/gr6.rb. Most likely joy/fear are too close. Other than that, the rest seems on point.

ccoupe commented 8 years ago

Funny you should mention that. The code is

// TODO: user specified radius multipler
double radius = chart->radius * 1.15; // extend it to draw outside

I think it was set to 1.10 for the gr7 plot. So, another something: has to be added to the API. sigh.

IanTrudel commented 8 years ago

By the way, I also notice labels/data are drawn clockwise. It seems every engine draw counter-clockwise. What do you think?

ccoupe commented 8 years ago

labels/data are drawn clockwise

We've been here before - dueling conventions. Oddly enough, I use the most common C idiom of for (i = 0; i < max; i++) instead of the error prone for (i= max; i > 1; i--) or is it for (i = max-1; i >=0; i--)?

What do you think?

I think I'll wait for someone else to cross that mine field and show me their C code.