sciapp / gr

GR framework: a graphics library for visualisation applications
Other
329 stars 54 forks source link

setcolorrep seems to set the wrong colors? #64

Open nilsbecker opened 5 years ago

nilsbecker commented 5 years ago

hi, i fear i am not understanding something. i try this:

In [57]: for (i, c) in zip([211,212,213],np.eye(3)):
    ...:     gr.setcolorrep(i, *c)
    ...:

In [58]: def upd():
    ...:     gr.clearws()
    ...:     for (c, n) in zip([211,212,213], [n1,n2,n3]):
    ...:         gr.setlinecolorind(c)
    ...:         gr.polyline(range(2000), n)
    ...:     gr.updatews()
    ...:

where upd is the update function called in the animation loop, and n1, n2, n3 are changing buffers. this works, but the colors are not red green and blue as i would have expected from the docs?

nilsbecker commented 5 years ago
In [72]: [gr.inqcolor(i) for i in [211,212,213]]
Out[72]: [255, 65280, 16711680]

this is on os x

FlorianRhiem commented 5 years ago

What type of output are you using? GKSTerm? What does your output look like? For me the following program yields red, green and blue lines:

import numpy as np
import gr

gr.setviewport(0, 1, 0, 1)
gr.setwindow(0, 2000, 0, 2000)
n1 = range(2000)
n2 = range(100, 2100)
n3 = range(200, 2200)

for (i, c) in zip([211,212,213],np.eye(3)):
    gr.setcolorrep(i, *c)

gr.clearws()
for (c, n) in zip([211,212,213], [n1, n2, n3]):
    gr.setlinecolorind(c)
    gr.polyline(range(2000), n)
gr.updatews()

image


The values returned by gr.inqcolor are the integer representations of the colors, as used e.g. in gr.drawimage. A simple way to get RGB data from this is:

red, green, blue = np.array([gr.inqcolor(i)], np.uint32).view(np.uint8)[:3]

With gr.setcolorrep taking 3 floats as arguments it would make sense to also return floats, but I'm not sure whether any users already rely on being able to get the integer representation via gr.inqcolor.

nilsbecker commented 5 years ago

hm. i am using gksterm and i get the same as you for your example program. no idea why i got something else before. i will try to reproduce my problem...

nilsbecker commented 5 years ago

hm. i get the right colors now. i think it might have to do with the order of gr.setviewport (creating a window) and gr.setcolorrep? do i have to initialize before tinkering with the colors?

nilsbecker commented 5 years ago

i found a case where it does not appear to work correctly.

import numpy as np

from matplotlib.colors import colorConverter as col

import gr
from gr.pygr import mlab

# species colors
colors = [col.to_rgb('xkcd:' + c) for c in
    ['dark plum', 'peach', 'dusty teal', 'light blue', 'salmon', 'chartreuse']
    ]

for (i, c) in zip(range(10,100), colors):
    gr.setcolorrep(i, *c)

c2 = np.eye(3)

mlab.figure()
mlab.colormap(None)
for (i, c) in zip(range(1, 100), colors):
    gr.setcolorrep(i, *c)
n1 = range(2000)
n2 = range(100, 2100)
n3 = range(200, 2200)
mlab.plot(n1, n1, n1, n2, n1, n3)
nilsbecker commented 5 years ago

i guess i don't understand in what order the colors in the colormap are used?!

nilsbecker commented 5 years ago

would it be easier to just switch to matplotlib with gr backend?

FlorianRhiem commented 5 years ago

This is not related to colormaps. The mlab.plot function uses a list of pre-defined colors for the plots. If you don't like these colors, you can either change which you use by passing a linespec to the mlab.plot function, e.g. mlab.plot(x, y, 'r') for a red line. If you want to use fully custom colors, you will need to change the colors with indices above 980, using a series of offsets. Alternatively, to avoid these offsets, you can pass a line spec to the plot function and then change the corresponding color.

For example this code:

from matplotlib.colors import colorConverter as col

import gr
from gr.pygr import mlab

colors = [col.to_rgb('xkcd:' + c) for c in
    ['dark plum', 'peach', 'dusty teal']
]

n1 = range(2000)
n2 = range(100, 2100)
n3 = range(200, 2200)
gr.setcolorrep(984, *colors[0])
gr.setcolorrep(987, *colors[1])
gr.setcolorrep(989, *colors[2])
mlab.plot(n1, 'r', n2, 'g', n3, 'b')

will produce the following output: image

Alternatively, you could achieve the same output using mlab.oplot and setting the color for each part of the plot:

from matplotlib.colors import colorConverter as col

import gr
from gr.pygr import mlab

colors = [col.to_rgb('xkcd:' + c) for c in
    ['dark plum', 'peach', 'dusty teal']
]

n1 = range(2000)
n2 = range(100, 2100)
n3 = range(200, 2200)
gr.setcolorrep(984, *colors[0])
mlab.plot(n1, 'r')
gr.setcolorrep(984, *colors[1])
mlab.oplot(n2, 'g')
gr.setcolorrep(984, *colors[2])
mlab.oplot(n3, 'b')
nilsbecker commented 5 years ago

ah ok, sorry for the noise. mlab is just replicating the api of matlab/pylab. i thought the standard color sequence must be the first ones in the colormap -- wrong!

nilsbecker commented 5 years ago

hm, i think i'm almost there but am still getting results that are a bit off, for instance wrong frame color etc.

# species colors
colors = [col.to_rgb('xkcd:' + c) for c in
    ['dark plum', 'peach', 'dusty teal', 'light blue', 'salmon', 'chartreuse'] ]

# magic to change the default colors for lines in pygr.mlab as per github
gr_standard_seq = 980 + np.array([9, 2, 0, 1, 16, 3, 15, 8, 6, 10, 11, 4, 12, 13, 14, 7, 5, 17, 18, 19])
def apply_colors():
    for (i, c) in enumerate(colors): gr.setcolorrep(gr_standard_seq[i], *c)

i then call apply_colors either before or after mlab.figure(). this changes line colors but also the frame, and seems off by a little bit. should this work?

FlorianRhiem commented 5 years ago

Yes, this should work. There might be a setlinecolorind missing before the drawing of the frame. However I am unable to reproduce this, here is the example I tried:

import numpy as np
import gr
import gr.pygr.mlab as mlab
from matplotlib.colors import colorConverter as col

colors = [col.to_rgb('xkcd:' + c) for c in
    ['dark plum', 'peach', 'dusty teal', 'light blue', 'salmon', 'chartreuse'] ]

gr_standard_seq = 980 + np.array([9, 2, 0, 1, 16, 3, 15, 8, 6, 10, 11, 4, 12, 13, 14, 7, 5, 17, 18, 19])
def apply_colors():
    for (i, c) in enumerate(colors): gr.setcolorrep(gr_standard_seq[i], *c)

x = np.linspace(-1, 1, 10)

apply_colors()
mlab.plot(x, x**2, x, x**3, x, x**4)

apply_colors()
mlab.plot(x, x**2, x, x**3, x, x**4)

apply_colors()
mlab.plot(x, x**2, x, x**3, x, x**4)

The result looks correct: image

Could you post a minimal working example that results in a wrongly colored frame?

nilsbecker commented 5 years ago

aha! now we're getting somewhere. i get this when i copy-and-paste your example:

screen shot 2018-10-19 at 09 42 07

this is macos 10.13.6, gr 1.5.1. currently i am running another gr3 window in another process in the background. is there some system-wide global state that may make them interact? edit: no, it's the same without the background process

nilsbecker commented 5 years ago

ok, this is confusing. if i run your example without calling apply_colors, i the the same result i posted above?!

FlorianRhiem commented 5 years ago

So you get an orange frame when calling this code?

import numpy as np
import gr
import gr.pygr.mlab as mlab
from matplotlib.colors import colorConverter as col

colors = [col.to_rgb('xkcd:' + c) for c in
    ['dark plum', 'peach', 'dusty teal', 'light blue', 'salmon', 'chartreuse'] ]

gr_standard_seq = 980 + np.array([9, 2, 0, 1, 16, 3, 15, 8, 6, 10, 11, 4, 12, 13, 14, 7, 5, 17, 18, 19])
def apply_colors():
    for (i, c) in enumerate(colors): gr.setcolorrep(gr_standard_seq[i], *c)

x = np.linspace(-1, 1, 10)

mlab.plot(x, x**2, x, x**3, x, x**4)
mlab.plot(x, x**2, x, x**3, x, x**4)
mlab.plot(x, x**2, x, x**3, x, x**4)

Have you kept GKSTerm running continuously since you've tried setting colors including color 1? If so, the color might still be set to whatever you set it to (apparently orange/peach). Try running gr.setcolor(1, 0, 0, 0) once to set color 1 to black again, then run the example again.

nilsbecker commented 5 years ago

ah, ok. i did run exactly your just posted code. i quite ipython before doing that but in fact GKSTerm was not killed. so now i manually killed GKSTerm, restarted ipython and ran the code. i now get a black frame and the standard colors.

finally, i did the same including killing GKSTerm with your original code. now i get your result.

in conclusion: i did not account for the fact that GKSTerm keeps global state even when the window is closed. when killin GKSTerm each time, everything works as expected.

side note: is this the desired behavior of GKSTerm? apparently it's not a child process of the python session that imports gr, otherwise it should not survive ending the ipython session...