Menu

Full RGB Colours

Help
2010-05-09
2012-10-16
  • Nobody/Anonymous

    Hello,

    I am trying to provide full RGB colour setting of plots to users of my
    program, however it doesn't appear that mathgl supports this? I tried to use
    gr->SetScheme("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), but
    this gives a linker error when compiling my code. (mathgl-1.10.1)

    The above ->SetScheme seemed like a bit of a hack, as the MGL documentation
    says it supports up to 100 colours in the pallette, but I have no idea if any
    of the characters are reserved, ie are there any limitations on the scheme
    string. So I only get 52 colours in the pallette (if the above actually
    worked, which it doesn't).

    • mycae (who may be at) yahoo.com
     
  • Nobody/Anonymous

    Sorry, forgot my question...

    1) In the event of the linker error, is there anything I can do to fix this?
    The default MGL pallette string is only 14 chars, and provides too few unique
    colours for may application
    2) Is there a better way to try to emulate full RGB colours? Sometimes the
    pallette is useful, other times I find myself trying to work around it.

     
  • Alexey Balakin

    Alexey Balakin - 2010-05-11

    1) About linker error -- can you give the error message and/or part of code.
    Because gr->SetScheme("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
    itself don't produce the error.

    2) Function SetScheme() set the coloring scheme for surfaces, 3d plots,
    contours and so on. It use up to 32 colors (first specified 32 colors in the
    string, which can be one of "kwrgbcymhWRGBCYMHlenpquLENPQU") -- see Sec.1.4.3
    of MathGL documentation.

    For automatic coloring of 1D plots (like Plot, Step, Stem, Area and so on)
    MathGL use palette which can contain up to 100 colors. At this one color is
    used for whole curve/plot. Palette can be specified by string (function
    SetPalette() ) or by RGB values (functions SetPalColor() and SetPalNum() ).
    These functions are described in Sec.3.1.8 of MathGL documentation.

    The set of color ids (characters "kwrgbcymhWRGBCYMHlenpquLENPQU") and its RGB
    values are specified internally in MathGL and cannot be changed right now.
    This limitation is connected with the requirement to specify extra parameters
    (line/surface styles, marks, arrows and so on) in the same string
    unambiguously.

    In future, I may add a feature to redefine RGB colors for characters
    "kwrgbcymhWRGBCYMHlenpquLENPQU" ... but it may lead to human mistake in color
    specification ... i.e. if 'b' will correspond to red color ;)

    In principle, you can do it right now by redefine/change the values of array
    mglColorIds. Now it is defined as

    mglColorID mglColorIds[] = {{'k', mglColor(0,0,0)},
        {'r', mglColor(1,0,0)},     {'R', mglColor(0.5,0,0)},
        {'g', mglColor(0,1,0)},     {'G', mglColor(0,0.5,0)},
        {'b', mglColor(0,0,1)},     {'B', mglColor(0,0,0.5)},
        {'w', mglColor(1,1,1)},     {'W', mglColor(0.7,0.7,0.7)},
        {'c', mglColor(0,1,1)},     {'C', mglColor(0,0.5,0.5)},
        {'m', mglColor(1,0,1)},     {'M', mglColor(0.5,0,0.5)},
        {'y', mglColor(1,1,0)},     {'Y', mglColor(0.5,0.5,0)},
        {'h', mglColor(0.5,0.5,0.5)},   {'H', mglColor(0.3,0.3,0.3)},
        {'l', mglColor(0,1,0.5)},   {'L', mglColor(0,0.5,0.25)},
        {'e', mglColor(0.5,1,0)},   {'E', mglColor(0.25,0.5,0)},
        {'n', mglColor(0,0.5,1)},   {'N', mglColor(0,0.25,0.5)},
        {'u', mglColor(0.5,0,1)},   {'U', mglColor(0.25,0,0.5)},
        {'q', mglColor(1,0.5,0)},   {'Q', mglColor(0.5,0.25,0)},
        {'p', mglColor(1,0,0.5)},   {'P', mglColor(0.5,0,0.25)},
        {' ', mglColor(-1,-1,-1)},  {0, mglColor(-1,-1,-1)} // the last one MUST have id=0
    };
    

    Note that this array define ALL colors ids for ANY MathGL function
    (including newly defined palette and color scheme)!

     
  • Alexey Balakin

    Alexey Balakin - 2010-05-11

    One more comment. In color schemes (function SetScheme() ) you can also use
    "lighted" colors. So, there are 15 basic colors and up to 9*15=135 "lighted"
    colors.

     
  • Nobody/Anonymous

    I am still quite stuck on this, no matter what I try, I still can't emulate
    full RGB in the plot.

    Regarding the linker error, the code is quite large.. The bits that are
    probably most relevant are ( I removed all the actual drawing routines, and I
    still get the error (actual message after code) )

    in mathglPane.h/cpp:
    class MathGLPane : public wxPanel {
    Multiplot thePlot;
    mglGraphZB *gr;

    void render(wxPaintEvent &event);
    }
    void MathGLPane::render(wxPaintEvent &event)
    {
    if(!thePlot || !plotSelList)
    return;

    int w,h;
    w=0;h=0;

    GetClientSize(&w,&h);
    // Now draw them
    if(gr)
    delete gr;

    gr = new mglGraphZB(w,h);

    thePlot->drawPlot(gr);

    And in plot.h/cpp

    class Multiplot
    {
    vector<float> r,g,b;
    vector<float> regionR,regionG,regionB;

    void drawPlot(mglGraph *gr);
    };

    //Comment to avoid debian bug #564422 : only mathgl 1.9 exists
    //http://bugs.debian.org/cgi-
    bin/bugreport.cgi?bug=564422

    define MGL_GTE_1_10

    void Multiplot::drawPlot(mglGraph *gr) const
    {
    if(!xValues.size())
    return;

    //work out if we are going to use log mode here
    bool logarithmic=false;
    for(unsigned int ui=0;ui<xValues.size(); ui++)
    {
    if(logarithmicVec)
    logarithmic=true;
    }

    //work out the bounding box for the plot,
    //and where the axis should cross
    mglPoint axisCross;
    mglPoint min,max;
    if(applyUserBounds)
    {
    ASSERT(yUserMax > yUserMin);
    ASSERT(xUserMax > xUserMin);

    max.x =xUserMax;
    max.y=yUserMax;

    min.x =xUserMin;
    min.y =yUserMin;

    axisCross.x=min.x;
    axisCross.y=min.y;

    }
    else
    {
    //Don't apply log to user bounds, as the
    //value is auto-computed
    min.x = minX;
    min.y =minY;
    max.x = maxX;
    if(logarithmic && maxY > 0.0f)
    max.y =log10(maxY);
    else
    max.y=maxY;

    axisCross.x = minX;
    axisCross.y = 0;

    gr->Org=axisCross;
    }

    gr->Axis(min,max,axisCross);
    gr->Axis("xy");

    ifdef MGL_GTE_1_10

    gr->SetScheme("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
    for(unsigned int uj=0;uj<regions.size();uj++)<br>{
    ASSERT(uj < strlen(MGL_PALETTE_CHARS));
    gr->SetPalColor(uj+1,regionR,regionG,regionB);
    cerr << "Region :" << uj << " colour : (" << regionR
    }

    endif

    //Draw regions as faces perp to z.
    //this will colour in a region of the graph as a rectangle
    for(unsigned int ui=0;ui<xValues.size();ui++)
    {
    if(!visible)
    continue;

    for(unsigned int uj=0;uj<regions.size();uj++)
    {
    //Do not plot regions that do not belong to current plot
    if(plotOwnsRegion != uniqueIDHandler.getId(ui))
    continue;

    //Compute the alphabetical colour code, set above
    char colourCode;
    colourCode=MGL_PALETTE_CHARS;
    colourCode='\0';

    //Compute region bounds, such that it will not exceed the axis
    float rMinX, rMaxX, rMinY,rMaxY;
    rMinY = min.y;
    rMaxY = max.y;
    rMinX = std::max(min.x,regions.first);
    rMaxX = std::min(max.x,regions.second);

    //Prevent drawing inverted regions
    if(rMaxX > rMinX && rMaxY > rMinY)
    gr->FaceZ(rMinX,rMinY,-1,rMaxX-rMinX,rMaxY-rMinY,colourCode);
    }
    }
    //Prevent mathgl from dropping lines that straddle the plot region.

    ifdef MGL_GTE_1_10

    gr->SetCut(false);

    endif

    for(unsigned int ui=0;ui<xValues.size(); ui++)
    {

    mglData xDat,yDat;
    if(!visible)
    continue;

    float bufferX,bufferY;
    ASSERT(xValues.size() ==yValues.size());
    bufferX = new float[xValues.size()];
    bufferY = new float[yValues.size()];

    //I can't seem to get mathgl's logarithmic mode
    //to work. Just take log(data) as needed
    if(logarithmic)
    {
    for(unsigned int uj=0;uj<xValues.size(); uj++)
    {
    bufferX = xValues;

    if(yValues > 0.0)
    bufferY = log10(yValues);
    else
    bufferY = 0;
    }
    else
    {
    for(unsigned int uj=0;uj<xValues.size(); uj++)
    {
    bufferX = xValues;
    bufferY = yValues;
    }
    }

    xDat.Set(bufferX,xValues.size());
    yDat.Set(bufferY,yValues.size());

    char colourCode;
    colourCode=MGL_PALETTE_CHARS;
    colourCode='\0';

    //Set the ith pallete colour

    ifdef MGL_GTE_1_10

    //gr->SetScheme("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
    cerr << "Setting pallette colour " << ui +regions.size() + 1 << " to r:" << r
    << " g:" << g << " b:" << b << endl;
    gr->SetPalColor(ui+regions.size()+1,r,g,b);

    endif

    //Plot the appropriate form
    switch(plotTypes)
    {
    case PLOT_TYPE_LINES:
    //Unfortunately, when using line plots, mathgl moves the data points to the
    plot boundary,
    //rather than linear interpolating them back along their paths. I have emailed
    the author.
    //for now, we shall have to put up with missing lines, is better than
    "falsifying" data
    // :( Absolute worst case, I may have to draw them myself.

    ifdef MGL_GTE_1_10

    gr->SetCut(true);

    endif

    gr->Plot(xDat,yDat,colourCode);

    ifdef MGL_GTE_1_10

    gr->SetCut(false);

    endif

    break;
    case PLOT_TYPE_BARS:
    gr->Bars(xDat,yDat,colourCode);
    break;
    case PLOT_TYPE_STEPS:
    //Same problem as for line plot.

    ifdef MGL_GTE_1_10

    gr->SetCut(true);

    endif

    gr->Step(xDat,yDat,colourCode);

    ifdef MGL_GTE_1_10

    gr->SetCut(false);

    endif

    break;
    case PLOT_TYPE_STEM:
    gr->Stem(xDat,yDat,colourCode);
    break;
    default:
    ASSERT(false);
    break;
    }

    delete bufferX;
    delete bufferY;

    }
    ASSERT(xLabels.size() == yLabels.size());

    //FIXME: This should plot All labels, or admit that it cannot
    //fit them on the page. Not just the first
    //Xlabel
    if(xLabels.size())
    {
    string sX(xLabels.begin(), xLabels.end());
    sX.assign(xLabels.begin(), xLabels.end()); //unicode conversion
    gr->Label('x',sX.c_str());

    string sY(yLabels.begin(), yLabels.end());
    sY.assign(yLabels.begin(), yLabels.end()); //unicode conversion
    if(logarithmic)
    sY = string("\log(") + sY + ")";
    gr->Label('y',sY.c_str(),0);

    string sT(titles.begin(), titles.end());
    sT.assign(titles.begin(), titles.end()); //unicode conversion
    gr->Title(sT.c_str());
    }
    }

    and the error is
    plot.cpp:593: undefined reference to `mglGraph::SetScheme(char const*, bool)'

    Should I use the SVN version?

    The palette system is great if the colours I use don't matter, as it will give
    a nice result without me having to do anything. However as these need to match
    up to colours being read from a file, this is problematic for me, hence why I
    am trying to hijack the palette.

    I have tried using MGL_PALETTE_CHARS as

    const char MGL_PALETTE_CHARS= "krRgGbBwWcCmMyYhHlLeEnNuUqQpP";
    const char
    MGL_PALETTE_CHARS= "kwrgbcymhWRGBCYMHlenpquLENPQU";
    const char *MGL_PALETTE_CHARS=
    "abcdefghijklmnopqrstuvwxyzABCDEFHIJKLMNOPQRSTUVWXYZ"; //Use when using
    SetScheme

    I have tried:
    gr->SetPalColor(ui+regions.size(),r,g,b);
    gr->SetPalColor(ui+regions.size()+1,r,g,b);

    I cannot seem to get anything other than the mathgl default colours.

    Thanks for the help.

     
  • Alexey Balakin

    Alexey Balakin - 2010-05-14

    For first look everything is OK ... May I ask stupid question? Do you link
    with MathGL library (i.e. do you specify -lmgl for linker)? Is this problem
    only with SetScheme or with other MathGL functions too? Do you correctly
    install MathGL? Keep in mind that you may need to call "sudo ldconfig" if you
    install from sources (as it written in make file output).

    It is not necessary to use SVN version (for this case) since SetScheme is very
    old function.

    Once again, SetScheme set color scheme not palette! Color scheme is used
    for coloring surfaces, vector fields, contours and so on. Palette is used
    for automatic coloring only 1d curves and isn't used for surfaces and
    so on. Function SetPalColor() change palette it don't color scheme for
    surfaces!

    Also, you cannot change the ids for colors (i.e.
    "kwrgbcymhWRGBCYMHlenpquLENPQU"). And I don't understand what you want to
    receive by call
    gr->SetScheme("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); ???

    The only thing you can do is to change the RGB values for each color id --
    change mglColorIds variable. For example, if you want switch red and black
    colors then use

    mglColorIds = {{'k', mglColor(1,0,0)}, {'r', mglColor(0,0,0)}, // <- here

    {'R', mglColor(0.5,0,0)},
    {'g', mglColor(0,1,0)}, {'G', mglColor(0,0.5,0)},
    {'b', mglColor(0,0,1)}, {'B', mglColor(0,0,0.5)},
    {'w', mglColor(1,1,1)}, {'W', mglColor(0.7,0.7,0.7)},
    {'c', mglColor(0,1,1)}, {'C', mglColor(0,0.5,0.5)},
    {'m', mglColor(1,0,1)}, {'M', mglColor(0.5,0,0.5)},
    {'y', mglColor(1,1,0)}, {'Y', mglColor(0.5,0.5,0)},
    {'h', mglColor(0.5,0.5,0.5)}, {'H', mglColor(0.3,0.3,0.3)},
    {'l', mglColor(0,1,0.5)}, {'L', mglColor(0,0.5,0.25)},
    {'e', mglColor(0.5,1,0)}, {'E', mglColor(0.25,0.5,0)},
    {'n', mglColor(0,0.5,1)}, {'N', mglColor(0,0.25,0.5)},
    {'u', mglColor(0.5,0,1)}, {'U', mglColor(0.25,0,0.5)},
    {'q', mglColor(1,0.5,0)}, {'Q', mglColor(0.5,0.25,0)},
    {'p', mglColor(1,0,0.5)}, {'P', mglColor(0.5,0,0.25)},
    {' ', mglColor(-1,-1,-1)}, {0, mglColor(-1,-1,-1)}}; // the last one MUST have
    id=0

    Now if one type 'k' then he will obtain red color (not black as default) and
    if one type 'r' then he will obtain black color (not red as default). By the
    same manner you can change all colors. Of course such definition should be
    putted before any plotting functions.

     
  • Nobody/Anonymous

    Everything links and works OK as long as I do not use SetScheme, but I now
    understand your comment a bit better, and using setscheme is the completely
    wrong thing to do anyway, so I do not need to solve this problem I guess...

    I shall try directly modifying mglColourIDs.

    Thanks.

     
  • Nobody/Anonymous

    Argh. I have worked out why it is not possible to have full RGB colour!
    (gdb) bt

    0 mglGraph::Plot (this=0xfd1a70, x=..., y=..., z=..., pen=0x7fffffffc170 "r")

    at mgl_1d.cpp:276

    1 0x00007ffff68c5002 in mglGraph::Plot (this=0xfd1a70, x=..., y=...,

    pen=0x7fffffffc170 "r", zVal=-1) at mgl_1d.cpp:302

    2 0x000000000045ff81 in Multiplot::drawPlot (this=0x918460, gr=0xfd1a70) at

    plot.cpp:508

    3 0x000000000045bdb6 in MathGLPane::render (this=0x904bd0, event=...) at

    mathglPane.cpp:106

    4 0x00007ffff5067550 in

    wxEvtHandler::ProcessEventIfMatches(wxEventTableEntryBase const&,
    wxEvtHandler*, wxEvent&) () from /usr/lib64/libwx_baseu-2.8.so.0

    5 0x00007ffff5068524 in wxEventHashTable::HandleEvent(wxEvent&,

    wxEvtHandler*) () from /usr/lib64/libwx_baseu-2.8.so.0

    6 0x00007ffff5068607 in wxEvtHandler::ProcessEvent(wxEvent&) () from

    /usr/lib64/libwx_baseu-2.8.so.0

    7 0x00007ffff54dd145 in wxWindow::GtkSendPaintEvents() () from

    /usr/lib64/libwx_gtk2u_core-2.
    (gdb) print pen
    $24 = 0x7fffffffc170 "r"
    (gdb) print this->pal
    There is no member or method named pal.
    (gdb) print this->Pal
    $25 = {{r = 0.239215687, g = 0.239215687, b = 0.443137258}, {r = 0, g = 1, b =
    0}, {r = 1, g = 0, b = 0}, {r = 0, g = 1, b = 1}, {r = 1, g = 0, b = 1}, {r =
    1, g = 1, b = 0}, {r = 0.5, g = 0.5, b = 0.5}, {
    r = 0, g = 1, b = 0.5}, {r = 0, g = 0.5, b = 1}, {r = 1, g = 0.5, b = 0}, {r =
    0.5, g = 1, b = 0}, {r = 0.5, g = 0, b = 1}, {r = 1, g = 0, b = 0.5}, {r =
    0.300000012, g = 0.300000012, b = 0.300000012},
    {r = 0, g = 0, b = 0} <repeats 87="" times="">}
    (gdb) n
    270 for (j=0; j<m; j++)<br="">(gdb) print this->pal
    There is no member or method named pal.
    (gdb) print this->Pal
    $26 = {{r = 1, g = 0, b = 0}, {r = 0, g = 0, b = 0} <repeats 100="" times="">}

    SetPal restores the default palette colours during the plot. :(.

    532 void mglGraph::SetPal(const char colors)
    533 {
    534 if(!colors || !colors) colors = DefPal; // restore default
    535 memset(Pal,0,100
    sizeof(mglColor));
    536 memset(PalNames,0,101*sizeof(char));
    537 int i,n = strlen(colors),k;
    538 n = n<100? n:100;
    539 for(i=k=0;i<n;i++)
    540 {
    541 if(!strchr("wkrgbcymhRGBCYMHWlenuqpLENUQP",colors_)) continue;
    542 PalNames = colors_; Pal = mglColor(colors_); k++;
    543 }
    544 NumPal = k; // CurrPal = 0;
    545 if(k==0) SetPal(0); // if no colors then set default palette
    546 }

    What to do???___

     
  • Nobody/Anonymous

    Sorry for all the posts. My current "solution" is to compute the min euclidean
    distance :(. I tried to patch the ::plot function, by removing the call to the
    Pen() and SetPal() functions. This succeded for a single graph, but not for
    multiple coloured plots.

    I really don't want to ship a non-standard mathgl with my application. That
    would be bad! If someone has a better way to set the colour by RGB, I am all
    ears.

    float distanceSqr=std::numeric_limits<float>::max();
    float distanceTmp;

    //mathgl's "named" colours
    const char *mglColourString="wkrgbcymhRGBCYMHWlenuqpLENUQP";
    const unsigned int numColours= strlen(mglColourString);

    mglColor c;
    char val;

    for(unsigned int ui=0;ui<numColours;ui++)
    {
    c.Set(mglColourString);

    distanceTmp= (c.r - r )(c.r - r ) +(c.g - g )(c.g - g )
    + (c.b - b )*(c.b - b );

    if(distanceSqr > distanceTmp)
    {
    distanceSqr = (distanceTmp);
    val = mglColourString;
    }

    }

    return val;
    }

     
  • Alexey Balakin

    Alexey Balakin - 2010-07-01

    Sorry for delay -- I check e-mail much often than forum ;) .

    Yes, I think this is unwanted feature ... I've just changed sources (in SVN).
    Now, default palette is restored only if current one is 1-color palette (i.e.
    after calls like Plot(dat,"r");). At this, the current palette (with user-
    defined RGB colors) should be used if no color is specified (i.e. for
    Plot(dat,"");).

    However, you still can redefine RGB colors for symbolic values (i.e. RGB in
    array mglColorIds) :).

     
  • Nobody/Anonymous

    Hi Alexy,

    Thanks for the comments and the source change. -- I think this should help.

    Just regarding forum/email. I prefer the forum for things that other people
    may find useful if it came up in a search engine (ie, others may have the same
    problem down the track), and email for things that others will not find
    useful.

    Thanks.

     
  • Alexey Balakin

    Alexey Balakin - 2010-07-05

    ok

     

Log in to post a comment.