Keeping extra info with each point #200

Open
dnschnur opened this Issue Sep 28, 2012 · 9 comments

1 participant

@dnschnur
Flot member

Original author: johanneswilm (March 01, 2009 18:52:13)

Hey,
until recently you used the data that came from javascript directly. This
was very clean and extended functionality in many ways not conceived by the
original flot creators.

For example, I make use of that to point a third data on every datapoint,
in order to give a unique pk (pk=primary key) to every value. Then I can
attach click functionality using this data, or make use of it in custom
point drawing.

Check my patch for custom point drawing, and then this function which i use
to draw bigger circles with labels for a certain subset of points:

function drawPoint(ctx,x,y,radius,plotOffset,dataitem,series) {
pk=dataitem[2];
if (eval(has_comments) && pk in comments) {
ctx.arc(x, y, radius*3, 0, 2 * Math.PI, true);
var seconddigit = commentCounter%26;
var firstdigit = Math.floor(commentCounter/26);
if (firstdigit > 26) {
firstdigit = firstdigit%26;
};
var label =''
if (firstdigit > 0) {
label+= String.fromCharCode(firstdigit+96);
};
label+= String.fromCharCode(seconddigit+97);
commentCounter+=1;
var comments_text="";
for (var i=0; i<comments[pk].length; i++) {
comments_text+="<p>"+comments[pk][i][0]+"</p>";
comments_text+="<p
class=&quot;signature&quot;>"+comments[pk][i][1]+"</p>";
};

    $(&quot;#&quot;+query_id+&quot;comments&quot;).append(&quot;&lt;tr class=\&quot;comment\&quot;&gt;&lt;td

valign=&quot;top&quot;><b>"+label+"</b></td><td valign=&quot;top&quot;>"+comments_text+"</td>$
var div = $('<div class="pointLabel"
id="'+pk+'">'+label+'</div>').insertAfter(this);
var labelwidth= $('#'+pk).outerWidth();
var leftOffset = plotOffset.left - (labelwidth/2) +.5;
this.next().css({
top: y,
left: leftOffset +x,
});
this.next().bind("click", function () {
if (!(comment_form_open)) {
var theDate = new Date(dataitem[0]);
var date = theDate.toDateString();
var label=series.label;
if (label=='') {
label='producto';
};
create_comment_form(dataitem[2],label,dataitem[1],date);
};
});

} else {
ctx.arc(x, y, radius, 0, 2 * Math.PI, true);
};
}

Original issue: http://code.google.com/p/flot/issues/detail?id=121

@dnschnur
Flot member

From olau%iol...@gtempaccount.com on March 01, 2009 21:17:31
Neat screenshot!

You can still access the original data, it's in the series[i].data array instead of
the series[i].datapoints.points array. At some points Flot has to support copying
more coordinates anyway so your hack might work then.

Also, no matter what you can always do something like this by maintaining a map from
something that identifies the points uniquely to the primary keys, e.g. (x,y) or
(series index, data array index) (you could concatenate them to a string with a ':'
in between). That's what I would have done in the first place.

I can't guarantee that internal data structures will stay the same, and there are
good reasons for abandoning the old model. One being that erratic input data is
propagated through-out Flot and may result in weird errors later on (I have gotten
quite a few reports on that kind of thing), another being that there's some
low-hanging fruit to be picked by simple input transformations.

Hope this answers your complaint.

@dnschnur
Flot member

From johanneswilm on March 01, 2009 23:51:46
Hmm, well the data needs to be send with pk-value from the server, because the graph
has the ability to add comments. So a translation would need to be calculated
client-side, and it would need to be updated for every comment that is add or deleted.
I am no expert on javascript resource usage, but that seems like kind of waste of
programing time and computer calculation time.

So until future patches make it possible for our patch to work again like you
mention, I think we'll have to stick with revision 136.

@dnschnur
Flot member

From johanneswilm on March 02, 2009 02:33:09
Hey, I looked through your sure code to see whether it would be possible to somehow
add a label for each datapoint again. However, it seems like you have switched to an
unusually complicated way of storing the datapoints.

First, you recover the data from the source:

x = data[j][0];
y = data[j][1];

The x and y values seem to be stored in one single long list like this:

points[k + 1] = y;
points[k] = x;

And then to get them out, you simply pick every other to get the x-values, and every
other to pick the y-value:

var x1 = points[i - incr], y1 = points[i - incr + 1],
x2 = points[i], y2 = points[i + 1];

Is there a point to that, or did it just seem the easiest?

why not instead store them as a list in a list like this:

points[k] = [x,y];

then you could read them like this

var x1 = points[i - incr][0], y1 = points[i - incr][1],
x2 = points[i][0], y2 = points[i][1];

And it would be relatively easy to add other data as with a simple patch, like this:

-points[k]=[x,y];

  • id = data[j][2]; +points[k]=[x,y,id];

And while the recovery of the main data would be the same:

var x1 = points[i - incr][0], y1 = points[i - incr][1],
x2 = points[i][0], y2 = points[i][1];

The id would easily be found like this:

var id1 = points[i - incr][2], id2 = points[i][2]

Of course the increment of i would have to be halved both in storing and recovering
data.

Now we need to store an id with every data. But I've seen another patch on the web
that's trying to just set single flags on some data points. I am sure there is quite
a lot of stuff people may want to associate with a datapoint directly, and so it
would really be great if Flot would be programmed in a way that would allow for
patches to add such functionality easily.

But maybe there is a good reason for why you need all the data in just one long list?

@dnschnur
Flot member

From olau%iol...@gtempaccount.com on March 02, 2009 14:54:25
I timed it last Friday, and on Firefox the old arrays-in-arrays representation was
about 10 times slower to construct. I have some users with very large datasets where
this overhead is not negligible. So that's why.

I appreciate that you have something working right now, but I don't think it's that
hard to port over. There are plenty of options. As I mentioned, if you don't want to
change the mapping around, you still have access to the original data in the series.
So you could just lookup your pk with a slight modification of your point drawing
callback change.

@dnschnur
Flot member

From olau%iol...@gtempaccount.com on May 25, 2009 19:46:03
I think this issue has morphed into a "would like an easy way to associate extra data
with each point". For anyone interested, this should be relatively easy to add to
Flot by adding a little bit of API and fixing the (hardcoded, half-baked) way point
size is currently determined, take a look in processData.

@dnschnur
Flot member

From rcave...@gmail.com on July 22, 2010 04:28:54
I tried to create an extra work around by putting an extra json variable series called extra. The only Issue I'm having is linking the variable number for extra extra[#] with the datapoints.

        if (item) {
            if (previousPoint != item.datapoint) {
                previousPoint = item.datapoint;

                $("#tooltip").remove();
                var x = item.datapoint[0].toFixed(2),
                    y = item.datapoint[1].toFixed(2);

                if(item.series.label == 'Breakfast - Your Rating')
                        {
                            showTooltip(item.pageX, item.pageY,
                            item.series.label + " of " + x + " = " + y + ' & Item.extra = ' + item.series.extra[0]); //this is the line I'm talking about.  Is there a variable here that would link me to the data that's in x and y?  
                        }
                    else if(item.series.label == 'Breakfast - Food Markit Rating')
                    {
                            showTooltip(item.pageX, item.pageY,
                            item.series.label + " of " + x + " = " + y);
                    }
            }
        }

Bob

@dnschnur
Flot member

From rcave...@gmail.com on July 22, 2010 21:02:01
Solved my issue, here's what I did...

Sent 2 extra values to the page along with extra(to store message): extray, and extrax (to check against x and y coordinates on the graph) and use a counter to retrieve the index for extra.

$.each(item.series.extra, function(){
if(x==(item.series.extrax[counter]+'.00'))
{
if(y==(item.series.extray[counter]+'.00'))
{
showTooltip(item.pageX, item.pageY,'Extra value will be'+item.series.extra[counter]);
}
}
counter++;
});

I'm sure it's not the most efficient way to solve this issue, but solved for my needs.

@dnschnur
Flot member

From aromo...@gmail.com on September 28, 2010 22:32:08
you can use item.dataIndex to get the index of the data point corresponding to the x,y postion on the graph:

        showTooltip(item.pageX, item.pageY, item.series.tooltip[item.dataIndex]);

where tooltip is an extra array (corresponding to extras in the above example) of the comments you want to display in the tooltip.

@dnschnur
Flot member

From dnsch...@gmail.com on May 07, 2012 23:07:43
This is all possible in Flot right now; just not super-easy. I'm treating this as an enhancement request for spending some time to investigate alternatives that would make this simpler without sacrificing performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment