ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  When parallel coordinate would be supported?
Posted by dbsx on Jul-29-2019 17:01
I currently need to draw a figure with relation of several variables( more than 2). That is why I need parallel coordinate. But it seems that ChartDirector is not ready for it.

It is like this: https://plot.ly/python/parallel-coordinates-plot/

  Re: When parallel coordinate would be supported?
Posted by Peter Kwan on Jul-30-2019 06:02
Attachments:
Hi dbsx,

ChartDirector has a very flexible API, and it should not be difficult to create this type of charts. For example, You can add multiple axes to a chart, auto-scale them, and then use BaseChart.addLine to add custom line segments. Below please find an example for your reference:



#!/usr/bin/python
from pychartdir import *

data0 = [1700, 400, 46, 0.84]
data1 = [3900, 550, 68, 0.82]
data2 = [2900, 670, 35, 0.82]
data3 = [3800, 990, 33, 0.38]

allData = [data0, data1, data2, data3]

# Create a XYChart object of size 700 x 360 pixels. Use a vertical gradient color from sky blue
# (aaccff) to white (ffffff) as background. Set border to grey (888888). Use rounded corners. Enable
# soft drop shadow.
c = XYChart(700, 360)

# Set the plotarea at (50, 80) and of size 600 x 230 pixels.
c.setPlotArea(50, 80, 600, 230, Transparent, Transparent, Transparent, Transparent, Transparent)

# Create axes
leftAxis = c.yAxis()
cLeftAxis = c.addAxis(Left, -200)
cRightAxis = c.addAxis(Left, -400)
rightAxis = c.addAxis(Left, -600);

allAxes = [leftAxis, cLeftAxis, cRightAxis, rightAxis]
allNames = ["AAA", "BBB", "CCC", "DDD"]

# Find the data for each axis to auto-scale them
for i in range(len(allAxes)) :
dataForAxis = map(lambda a: a[i], allData)
allAxes[i].setColors(0xaaaaaa, 0x444444)
allAxes[i].setTitle(allNames[i]).setAlignment(Top)
allAxes[i].setLinearScale(min(dataForAxis), max(dataForAxis))
c.layoutAxes()

#Draw the lines
lineColors = [0xcc0000, 0x0000cc, 0x880080]
for i in range(len(allData)) :
data = allData[i]
yCoor = map(lambda j: c.getYCoor(data[j], allAxes[j]), range(len(data)))
for j in range(0, len(data) - 1) :
c.addLine(50 + j * 200, yCoor[j], 50 + (j + 1) * 200, yCoor[j + 1], lineColors[j], 1)

# Output the chart
c.makeChart("parallel_axis.png")


Hope this can help.

Regards
Peter Kwan
parallel_axis.png

  Re: When parallel coordinate would be supported?
Posted by Peter Kwan on Jul-30-2019 06:06
Attachments:
Hi dbsx,

I have just found out in your example it uses a different coloring scheme for the lines. I have modified to code to use a similar scheme:


#!/usr/bin/python
from pychartdir import *

data0 = [1700, 400, 46, 0.84]
data1 = [3900, 550, 68, 0.82]
data2 = [2900, 670, 35, 0.82]
data3 = [3800, 990, 33, 0.38]

allData = [data0, data1, data2, data3]

# Create a XYChart object of size 700 x 360 pixels. Use a vertical gradient color from sky blue
# (aaccff) to white (ffffff) as background. Set border to grey (888888). Use rounded corners. Enable
# soft drop shadow.
c = XYChart(700, 360)

# Set the plotarea at (50, 80) and of size 600 x 230 pixels.
c.setPlotArea(50, 80, 600, 230, Transparent, Transparent, Transparent, Transparent, Transparent)

# Create axes
leftAxis = c.yAxis()
cLeftAxis = c.addAxis(Left, -200)
cRightAxis = c.addAxis(Left, -400)
rightAxis = c.addAxis(Left, -600);

allAxes = [leftAxis, cLeftAxis, cRightAxis, rightAxis]
allNames = ["AAA", "BBB", "CCC", "DDD"]

# Find the data for each axis to auto-scale them
for i in range(len(allAxes)) :
dataForAxis = map(lambda a: a[i], allData)
allAxes[i].setColors(0xaaaaaa, 0x444444)
allAxes[i].setTitle(allNames[i]).setAlignment(Top)
allAxes[i].setLinearScale(min(dataForAxis), max(dataForAxis))
c.layoutAxes()

#Draw the lines
lineColors = [0xcc0000, 0x0000cc, 0x880080, 0x00cc00]
for i in range(len(allData)) :
data = allData[i]
yCoor = map(lambda j: c.getYCoor(data[j], allAxes[j]), range(len(data)))
for j in range(0, len(data) - 1) :
c.addLine(50 + j * 200, yCoor[j], 50 + (j + 1) * 200, yCoor[j + 1], lineColors[i], 1)

# Output the chart
c.makeChart("parallel_axis.png")



Regards
Peter Kwan
parallel_axis.png

  Re: When parallel coordinate would be supported?
Posted by dbsx on Jul-30-2019 10:03
Hi Peter,

Thanks for your reply. Currently, I am working  with C++/QT,  so I would try to figure it out with the Python version.

And Just 1 suggestion, this kind of chart plotting can be listed as another type of chart in official document.

Regards,
Dbsx

  Re: When parallel coordinate would be supported?
Posted by Peter Kwan on Jul-30-2019 15:23
Hi dbsx,

If you need help in porting, please let me know. (I notice that the Python "map" function has no close equivalent in C++.) I should be able to port it easily.

Regards
Peter Kwan

  Re: When parallel coordinate would be supported?
Posted by dbsx on Aug-01-2019 22:23
Attachments:
Hi Peter,

Sorry for the late reply. I modified as follows:

```
void NewPlotEngine::draParallelCoordinateChart(QChartViewer* viewer) {
// // The data for the line chart
double data0[] = {1700, 400, 46, 0.84};
double data1[] = {3900, 550, 68, 0.82};
double data2[] = {2900, 670, 35, 0.82};
double data3[] = {3800, 990, 33, 0.38};
std::vector<double*> allData = {data0, data1, data2, data3};

XYChart* c = new XYChart(700, 360);

c->setPlotArea(50, 80, 600, 230, Transparent, Transparent, Transparent,
   Transparent, Transparent);
// Create axes
auto leftAxis = c->yAxis();
auto cLeftAxis = c->addAxis(Left, -200);
auto cRightAxis = c->addAxis(Left, -400);
auto rightAxis = c->addAxis(Left, -600);

//
std::vector<Axis*> allAxes = {leftAxis, cLeftAxis, cRightAxis, rightAxis};
QStringList allNames = {"AAA", "BBB", "CCC", "DDD"};

// Find the data for each axis to auto - scale them
for(size_t i = 0 ; i < allAxes.size() ; i++) {
allAxes[i]->setColors(0xaaaaaa, 0x444444);
std::string myStr = allNames[i].toStdString();
const char* title = myStr.data();
allAxes[i]->setTitle(title)->setAlignment(Top);
// dataForAxis = map(lambda a : a[i], allData)
// allAxes[i].setLinearScale(min(dataForAxis), max(dataForAxis))
std::vector<double> dataForOneAxis;
for(auto& j : allData) {
dataForOneAxis.push_back(j[i]);
}
const auto maxV = *std::max_element(dataForOneAxis.begin(),
dataForOneAxis.end());
const auto minV = *std::min_element(dataForOneAxis.begin(),
dataForOneAxis.end());
allAxes[i]->setLinearScale(minV, maxV);
c->layoutAxes();
}
//Draw the lines
const long lineColors[] = {0xcc0000, 0x0000cc, 0x880080};
// for i in range(len(allData)) :
// data = allData[i]
for(size_t i = 0 ; i < allData.size() ; i++) {
const auto data = allData[i];
std::vector<int> yCoor;
for(size_t j = 0 ; j < allAxes.size() ; j++) {
yCoor.push_back(c->getYCoor(data[j], allAxes[j]));
}
for(size_t k = 0 ; k < allAxes.size() - 1 ; k++) {
c->addLine(50 + k * 200, yCoor[k], 50 + (k + 1) * 200, yCoor[k + 1],
   lineColors[i], 1);
}
// for(size_t j = 0 ; j < allAxes.size() ; j++) {
// yCoor.push_back(c->getYCoor(data[j], allAxes[j]));
// if(j > 0 && j < allAxes.size()) {
// // for j in range(0, len(data) - 1) :
// // c.addLine(50 + j * 200, yCoor[j], 50 + (j + 1) * 200, yCoor[j + 1], lineColors[i], 1)
// c->addLine(50 + (j-1) * 200, yCoor[j-1], 50 + j * 200, yCoor[j],
//    lineColors[i], 1);
// }
//
// }
}
// Output the chart
// c->makeChart("multiline.png");
delete viewer->getChart();
viewer->setChart(c);
}
```

But the output Pic is something wrong, I cannot figure it out at present.
Besides, I guess it is possible to exchange two coordinates position with mouse, right?

Regards,
Dbsx
errPic.png

  Re: When parallel coordinate would be supported?
Posted by Peter Kwan on Aug-02-2019 02:16
Hi dbsx,

Sorry for the confusion code. The original Python code contains leading spacing entered as "tab" characters. However, when the code is copy and pasted to the forum form, the "tab" character has no effect, and so all leading spacing are gone, and it is not clear what is the structure of the for loop. The original for loop should be:

for i in range(len(allAxes)) :
    dataForAxis = map(lambda a: a[i], allData)
    allAxes[i].setColors(0xaaaaaa, 0x444444)
    allAxes[i].setTitle(allNames[i]).setAlignment(Top)
    allAxes[i].setLinearScale(min(dataForAxis), max(dataForAxis))
c.layoutAxes()

So the c->layoutAxes(); should be outside the loop, not inside it. In C++, it should be:

for(size_t i = 0 ; i < allAxes.size() ; i++) {
    allAxes[i]->setColors(0xaaaaaa, 0x444444);
    std::string myStr = allNames[i].toStdString();
    const char* title = myStr.data();
    allAxes[i]->setTitle(title)->setAlignment(Top);
    // dataForAxis = map(lambda a : a[i], allData)
    // allAxes[i].setLinearScale(min(dataForAxis), max(dataForAxis))
    std::vector<double> dataForOneAxis;
    for(auto& j : allData) {
        dataForOneAxis.push_back(j[i]);
    }
    const auto maxV = *std::max_element(dataForOneAxis.begin(),
        dataForOneAxis.end());
    const auto minV = *std::min_element(dataForOneAxis.begin(),
        dataForOneAxis.end());
    allAxes[i]->setLinearScale(minV, maxV);
}
c->layoutAxes();


To "exchange two coordinates position with mouse", do you mean to exchange the positions of two axes?

In general, you can change the chart with the mouse. It is just by redrawing the chart when mouse action occurs. For example, consider the "Interactive Financial Chart" sample code that comes with ChartDirector. In this chart, the mouse can be used to add/remove indicator charts or lines or bars. The code just contains one method to draw the chart, using "flags" and "parameters" to enable/disable the lines and charts. The mouse action just change the flags, then redraw the chart.

Another example is the "Interactive Surface Chart" in the library section of our web site:

https://www.advsofteng.com/tutorials/interactive_surface_chart/interactive_surface_chart.html

In the code, there is only one method to draw the surface, and there are two parameters for the elevation and rotation angles. In the mouse move event handler, the code changes these two parameters based on how the mouse moves, then redraw the chart.

So for your case, you can set up some flags or parameters for things you want to be changeable by the mouse. Then the mouse action occurs, you can change the flags or parameters, and redraw the chart.

Regards
Peter Kwan

  Re: When parallel coordinate would be supported?
Posted by dbsx on Aug-02-2019 22:40
Hi Peter,

Thanks for reply. Now it is working. And for other related issue, I would try to figure it out by myself first.

Regards,
Dbsx