Request for plaintext statistics

I’d like to request that stats be accessible as plaintext (and therefore scrape-able) in the page source for a user’s profile.

It would make it simpler for third parties to compile statistics, lightening the burden for the Eyewire developers.

As an example, the ‘Folding at Home’ project which similarly relies on volunteers to perform scientific research (via donating computing power) exposes users’ stats simply and this has given rise to sites like Extreme Overclocking providing very fine-grained historical data.

This is great for setting up competitions and teams and other simple motivators for participation.

(It also appeals to me to be able to scrape and record my own data!)

Regardless, thanks for setting up a great tool/game!

1 Like

Hey Ruthalas,

This isn’t quite as convenient as what you’re talking about but it’s close.

Try pinging the following URL with a logged in session cookie:

You’ll get some useful profile information in JSON format. :smile:

Will S.
EyeWire Developer


My god…

I could use this to create forum signature banners!

Let the PHP begin!

EDIT: How often does each user’s stats get updated? Or are these values real time?


That is perfect! May thanks for the direction sapphiresun!

1 Like

Okay, I’m having a bit of trouble understanding the fscore array. To my understanding, accuracy is determined with the formula tp/(tp+fn), right? I tried using the numbers on my own stats, then comparing it to what is displayed in the EW interface, and I get slightly different values. Am I supposed to do something with fp as well, or is that just there to assist in calculating over/under colouring?

1 Like

Hey Higaran!

Happy to see you again. :slight_smile: I remember you showed me your sick setup a while back.

You’re partially right. tp / (tp + fn) is a measure known as “Recall”. 1 - recall = undercoloring.

tp / (tp + fp) is another measure called “Precision”. 1 - precision = overcoloring.

Your accuracy is a measure known as fscore (or F1) which is the harmonic mean of precision and recall. If you’ve ever wired circuits in parallel and computed the resistance you’re familiar with this setup although there’s an odd factor of 2 just hanging out in this one:

1 / 2f = 1 / p + 1 / r
f = 2 (pr) / (p + r) EDIT: This used to be flipped incorrectly.

Where f is your fscore, p is precision, and r is recall.

Hope that helps!

1 Like

Glad that helped Ruthalas! The values are realtime Hiigaran.:smile:

1 Like

Hmm, I tried following the formula and plugging my own fscore data into it, but it’s giving me an incorrect value. I must be doing something wrong…


Precision: tp/(tp+fp)
1 - P
P = 2033804/(2033804+142702)

Recall: tp/(tp+fn)
1 - R
R = 2033804/(2033804+79114)

f = 2 (p + r) / (pr)
2* ( (1-(2033804/(2033804+142702))) + (1-(2033804/(2033804+79114)))) / ((1-(2033804/(2033804+142702))) * (1-(2033804/(2033804+79114))) )

Taking the fscore data directly from the JSON, so those are definitely correct, and im taking my accuracy value from the EW interface. Since it is real time, it should be showing 94.8%, but when I try to follow the formula and plug the values in on the second last line, I get roughly 84%.

1 Like

Whoops. Sorry, I made a boo boo in my above algebra.

F = 2 * (P * R) / (P + R)

I forgot to do one of the inversions (I was doing it all in my head while I was waking up haha).

Here’s what I got from the computation:

> tp = 2033804
> fp = 142702
> fn = 79114
> p = tp / (tp + fp)
> r = tp / (tp + fn)
>f1 =  2 * p*r / (p + r)

It’s also important to note that in your calculation you’re using the values for undercoloring and overcoloring. Those are merely derivative values from precisions and recall that make it easier to understand your performance. The F-score is computed from precisions and recall directly.

Hope that helps!

  • Will
1 Like

For what it’s worth, here’s the JavaScript code that computes your F-Score for the progress bar in EyeWire:

fScore = function (args) {
	args = args || {};

	var tp =;
	var fp = args.fp;
	var fn = args.fn;

	if (tp + fp + fn === 0) {
		return {
			fscore: 0,
			precision: 0,
			recall: 0

	var precision = tp / (tp + fp);
	var recall = tp / (tp + fn);

	var fscore = 2 * tp / (2 * tp + fp + fn);

	return {
		fscore: fscore,
		precision: precision,
		recall: recall

The fscore looks a little weird because, in my great enthusiasm to more fully understand the fscore years ago, I simplified the algebra to reduce it to tp, fp, and fn. Nowadays I probably would have just done it in terms of precisions and recall as it’s easier to remember and verify. Either way is fine.

1 Like

Hmm, I’ve implemented a PHP variant of your JS as follows:



echo $accuracy;

I could probably simplify $accuracy a bit, but I have another issue to deal with first. This code works fine, and outputs the right value for 95% (if your eyes haven’t crossed at my lack of finesse with coding, you’ll see that I’m getting the average accuracy of L1 and L2). However, putting the $accuracy line into my main script gives me 98%.

So far I know that the formula works. I also know the data is correct, since I copied the values above from the local file I saved to the server. There must be something in my code, between the point where the data is read, to the point where the data is displayed, which is causing the value to be incorrect.

The search continues…

EDIT: Found the cause. My stupidity. I was missing two of the six variables. IT WORKS!


Haha, congrats! Let me know if I can help you guys with anything else.

Just as a tip, being neat in your coding from the start nearly always pays off. :wink:

1 Like

I have another question for you!

What does the discrepancy between the last line here indicate:

My data has all zeros there, while Hiigaran’s is filled with data.

1 Like

Good question! Notice that there are two confusion matricies shown inside of an array [ {}, {} ]

The first one corresponds to difficulty 1 cells (Mystery/Artifact), the second corresponds to level 2 cells (Starburst/Lightning/Relics).

If you look at your profile, it looks like you haven’t passes the level 2 training on this account. Time to get cracking if you want those zeros to turn into something else. :wink:



Ironically, it was in the neater part of my code that the problem was in.

As for that formula, I just threw it together quickly by substituting the formula provided, with the appropriate variables. I plan to improve that line later on though…

1 Like

It’s also possible to access points and cubes data for previous days using this URL:

Where the ‘user’ can be changed with ‘country’ to get per-country statistics, ‘points’ can be changed to ‘cubes’ to get completed cubes data (although it won’t tell you how many of those were trailblazes) and ‘day’ can be changed to ‘week’ or ‘month’ to get weekly and monthly data respectively.

The URL takes 2 GET parameters: from and to. Both of them are a date in YYYY-MM-DD format and can be used to get data in a specific timespan. For example, the URL

will return everyone’s points per day for the entire February.

Keep in mind that if the timespan is too large and the response is too big, the server will cut it short, so you can’t go requesting data from 2013 to 2016 in one request.


That is quite useful!

1 Like

After putting the finishing touches on the code, EyeWire functionality is a go!

This one is dedicated to all the Twinkle supporters of today’s challenge!

To ensure that EW servers aren’t bombarded with requests, user data is stored locally for an hour, and then requested from the server after that time whenever the image is loaded.

EDIT: Let me know if anyone is interested in the entire source code.


I am interested in how you specifically grabbed accuracies from fscore.
Edit: Ahhh…I got it. Thanks.