Introduction

32 views
Skip to first unread message

Rodrigo Araújo

unread,
Feb 16, 2009, 8:05:54 PM2/16/09
to cair...@googlegroups.com
Hi there guys,

Last time I checked, there were two other subscribers (besides me) on the group.
So, are you guys CairoPlot users? If so, are there any feature you'd like to request?

I don't know if you guys have been following the trunk updates, but a couple of new functions have been added:

- ScatterPlot are now supported with error bars;
- All plot classes now support custom colors through the series_colors or colors attributes;
- FunctionPlot now supports lists and dictionaries of functions;
- Bug fixes;

Also, I've been working on a theme mechanism for the user to select some pre-defined themes (like rainbow colors, red to yellow, black to red, etc) for the series. I'll be adding it to the trunk tomorrow.

Last, I and Magnun have been working on an implementation of the Series class which will hold all series' related data and will lead to a major code refactoring to turn the code easier to understand and modify.

All that said, let me hear something from you guys.

Cheers,

Rodrigo Araújo

Paul Eipper

unread,
Feb 16, 2009, 8:15:35 PM2/16/09
to cair...@googlegroups.com
2009/2/16, Rodrigo Araújo <alf.r...@gmail.com>:

Hi there,

I actually am just interested in learning a bit of how to use Cairo in Python.

I really like the project, also because I recently had to implement a
few plotting functions myself (wxWidgets and C++) and would like to
see how they look in Python and Cairo, so maybe I'll mess with the
code a little.

Other than that, I'm here out of curiosity :)

--
Paul Eipper

Rodrigo Araújo

unread,
Feb 17, 2009, 11:35:22 AM2/17/09
to cair...@googlegroups.com
Nice.
What did you do exactly on C++?

Rodrigo Araujo

Paul Eipper

unread,
Feb 18, 2009, 2:15:59 PM2/18/09
to cair...@googlegroups.com
2009/2/17 Rodrigo Araújo <alf.r...@gmail.com>:

> Nice.
> What did you do exactly on C++?
> Rodrigo Araujo

It's a digital tachograph (vehicle monitoring hardware) viewer app,
that shows the recorded speed and distances as a graph.

I will probably try to port the odometer graph (a zigzag line graph)
to cairoplot to see how it looks like.

--
Paul Eipper

Andre von Houck

unread,
Feb 19, 2009, 8:36:16 PM2/19/09
to CairoPlot
For feature suggestions can we automatically bold out the zero X and Y
lines? Maybe even add ability specify user important lines.

Also can we have 0 be the "root" point starting for scale? And can we
have it try keeping it to "rounded values." I see stuff such as scale
running at 13.96, 8.47, 2.98 , -2.51, -8.00, -13.48 ... i would like
to see scaling running as 9,6,3,0,-3,6,9.

It should not be hard to notice if range is 2-4 marks should be
around .25 and if range is around 13 to -40 marks should be around 4
or 5 not 4.48783 as its figuring out now ...
maybe fitting stuff into most makes since range would fix the point on
top with the zoom.

Thanks!


On Feb 18, 11:15 am, Paul Eipper <lkrai...@gmail.com> wrote:
> 2009/2/17 Rodrigo Araújo <alf.rodr...@gmail.com>:

Rodrigo Araújo

unread,
Mar 6, 2009, 6:49:09 AM3/6/09
to cair...@googlegroups.com
Hi there Andre,

First, sorry for the long delay on answering you. Lots of problems at work.
So, for bolding the axis lines, it's easy. I'll analyse it later tonight.

About the labels I don't know an algorithm that could convert the calculated values into rounded ones without falling in the trap of creating repeated values. Could you suggest something?

Thanks for the interest!
Rodrigo Araújo

andre v

unread,
Mar 6, 2009, 7:59:59 PM3/6/09
to cair...@googlegroups.com
"About the labels I don't know an algorithm that could convert the
calculated values into rounded ones without falling in the trap of
creating repeated values. Could you suggest something?"

I don't exactly follow you about repeated values yet I have
implemented exactly what I wanted in the attachment.

I should probably get my own bzr branch for others to pull and I need
to clean up stuff.

After messing with it i think it needs to be broken out into more
accessible classes such as reusable themes and boundaries. Many
things can be improved:

I had a need to have one graph have the same boundaries (scaling) as
another graph but that did not work too well. It would be great to be
able to pull the boundaries out and have it apply to other graphs.
Even better have group of graphs deiced for best scale for them all.

Themes would be nice because my site designs are normally white on
black and some stuff is not that customizable. The 1st default yellow
color is particularly bad visibility on default white background.

There is still many problems with labels running into each other.
Some sort of label collision algorithm would be nice.

Donut charts should sort from high to low, right now its random.

Automatic chart key generation would be nice.

Maybe some tools to read off charts directly form csv files.

More chart types such as history line, stacked bar charts etc...
CairoPlot.py
shrunkTime.png
grow2.png

Rodrigo Araújo

unread,
Mar 6, 2009, 9:53:24 PM3/6/09
to cair...@googlegroups.com
Hi there Andre,

Thanks for all these ideas and colaboration. It's really great to see people using CairoPlot and, even greater, to see them suggesting new features and pointing bugs. I have a lot to say about your last email.



"I don't exactly follow you about repeated values yet I have
implemented exactly what I wanted in the attachment."

> I'm checking your algorithm right now to see how you did it. I'll be glad to add it to CairoPlot.

"After messing with it i think it needs to be broken out into more
accessible classes such as reusable themes and boundaries.  Many
things can be improved:"

> Well, I have a color theme implementation which I haven't committed yet. Right now it only lets the user define color themes for the series. It's like selecting the color steps that should be used and the algorithm interpolates the rest. I plan on adding backgrounds to this theme stuff too. 

"I had a need to have one graph have the same boundaries (scaling) as
another graph but that did not work too well.  It would be great to be
able to pull the boundaries out and have it apply to other graphs.
Even better have group of graphs deiced for best scale for them all." 

> Did you try the x_bounds and y_bounds parameters? They should work to let you define the boundaries of your graphic, or did I got the wrong idea?

"Themes would be nice because my site designs are normally white on
black and some stuff is not that customizable.  The 1st default yellow
color is particularly bad visibility on default white background."

> That default color is not all that great, but it's generated like that because of a random seed. But, whenever the user is not comfortable with the generated colors, he could go in and pass whatever he needs.

"There is still many problems with labels running into each other.
Some sort of label collision algorithm would be nice."

> This is a real big problem indeed. I'm thinking of measuring the size of the last drawn label and only drawing a new one when the x steps out of the last one.

"Donut charts should sort from high to low, right now its random."

> That one shall be easy to fix.

"Automatic chart key generation would be nice."

> I didn't quite get what you meant by chart key. Is it the name of the file? 

"More chart types such as history line, stacked bar charts etc..."

> Surely, I also thought of Polar charts.

Thanks again,

Rodrigo Araújo

Rodrigo Araújo

unread,
Mar 8, 2009, 11:37:30 AM3/8/09
to cair...@googlegroups.com
Hey Andre,

I've been trying to understand the code you sent me but I couldn't figure out how that works. Maybe you could document it and change your variable names to clearer names so I'd understand what you're doing.

As far as I got, I understood you scale_range function gets two bounds (a lower and an upper) and a number of steps (the ticks) and returns new bounds and a step to be used while creating the labels so they look better. The results are really good indeed.

Rgds,

Rodrigo Araujo

andre v

unread,
Mar 8, 2009, 2:00:27 PM3/8/09
to cair...@googlegroups.com
Commented here a bit:

def scale(n):
"""
returns the value truncated to one digit
23452345 -> 200000000
"""
d = 0
if n == 0 : return 0
while n < 1:
n *= 10.0
d -= 1
while n > 10:
n /= 10.0
d += 1
return int(n) * (10 ** d)

def scale_with(number,scale_range):
"""
returns a number scaled as much as it
has to with the given range
"""
exponent = 0
if number == 0 : return 0
# find the exponent of number
while scale_range < 1:
scale_range *= 10.0
number *= 10.0
exponent -= 1
while scale_range > 10:
scale_range /= 10.0
number /= 10.0
exponent += 1
# put all the zero's back
return int(number) * (10 ** exponent)

def stackable(number):
"""
finds closes nice number to given number
that can be stacked nicely as scale.
One of 1 2 2.5 5 + enough 0's to make it
match number's size.
"""
number *= 2
exponent = 0
if number == 0 :
# scale of zero? return 1 as best guess
return 1
# find the exponent of number
while number < 1:
number *= 10.0
exponent -= 1
while number > 10:
number /= 10.0
exponent += 1
# find best fitting digit
final_digit = 1
for good_digit in 1,2,2.5,5:
if number > good_digit : final_digit = good_digit
# put same number of 0's the same as the original number
return final_digit * (10 ** exponent)

def scale_range(a,b,ticks=11):
"""
given abounds a and b and number of ticks
returns new nicer range and tick size
nicer range should be bigger then a and b
if the range contains 0 it should fall on one of the ticks
tick size would stackable() number
"""
# find nice tick scale
tick_scale = stackable(abs(a-b)/ticks)
# find 2 scaled with ranges around tick_size
a1,b1 = scale_with(a,tick_scale),scale_with(b,tick_scale)
# find the zero_offset point
zero_offset = tick_scale*int((a+b)/2./tick_scale)
# use zero_offset as starting point and sub tract from there
a2 = zero_offset-tick_scale*int(ticks/2)
b2 = zero_offset+tick_scale*int(ticks/2)
while a2 > a or b2 < b:
# oops with all the computations we shrunk too much
# lets just expand and try again
a2,b2,tick_scale = scale_range(a-tick_scale,b+tick_scale)
return (a2,b2,tick_scale)

def nice_range(a,b,ticks=11):
"""
same as scale_range but only returns range not the
tick_scale
"""
return scale_range(a,b,ticks)[0:2]



def test():

assert scale(0.00734) == .007
assert scale(0.134) == .1
assert scale(2.123) == 2
assert scale(323) == 300
assert scale(1566) == 1000
assert scale(52345)== 50000

assert scale_with(0.00734,2) == 0
assert scale_with(0.134,500) == 0
assert scale_with(2.123,.01) == 2.12
assert scale_with(323,20) == 320
assert scale_with(1566,10) == 1566
assert scale_with(52345,1000000) == 0

assert stackable(0.00734) == 0.01
assert stackable(0.134) == 0.25
assert stackable(2.123) == 2.5
assert stackable(323) == 500
assert stackable(1566) == 2500
assert stackable(52345) == 100000

assert scale_range(0.00734,100) == (0, 100, 10)
assert scale_range(0.134,.4) == (0.0, 0.5, 0.05)
assert scale_range(2.123,400) == (-50, 450, 50)
assert scale_range(323,1234) == (-400, 1600, 200)
assert scale_range(1566,50034) == (-30000, 70000, 10000)
assert scale_range(52345,52348) == (52341, 52351, 1)
assert scale_range(59995,59998) == (59991, 60001, 1)
assert scale_range(0.151829983285, 10.1368263183) == (-6, 14, 2)

# lets test random scale ranges
from random import random,seed
seed(9)
for a in map(lambda x: (random()-.5) * 10 ** x ,xrange(10),):
for b in map(lambda x: (random()-.5) * 10 ** x ,xrange(10),):
a, b = min(a,b),max(a,b)
a1,b1,s = scale_range(a,b)
assert a1 < a
assert b1 > b
assert b1 - a1+s*10 > .000001
if a1 < 0 and b1 > 0 :
# if there is a zero in the range make sure we
# have a mark at zero too
r = [ int((a1+s*i)*1000) for i in range(11)]
assert 0 in r

test()


Some improvements to the algorithm might be having it start at 0 in
proper conditions. ( right now it only requires to have one of the
ticks at 0 ) because it looks kind of odd when you are counting kb of
memory used and you get negative memory and negative time because the
algo rescaled it that way.
Reply all
Reply to author
Forward
0 new messages