|
[MFC]starting point of x-axis |
Posted by Kaiden on Sep-25-2013 15:29 |
|
Hi Peter,
I still have a question to be answered by you, but here I am again.
Until now, my graphs the very left x-axis has been 0. Especially my histogram.
So, if I didn't place any labels the very left x-axis would start with 0 and increase as much
as the number of data which I want to draw.
but now, I need to change 'the very left x-axis' value each time I read a new data.
(so it's effect by the data that I read in)
'the very left of x-axis' should be smaller than the smallest value in data.
how can i do this?
Thanks,
Kaiden. |
Re: [MFC]starting point of x-axis |
Posted by Peter Kwan on Sep-26-2013 02:23 |
|
Hi Kaiden,
The x-axis scale can be configured using Axis.setLinearScale, and you can tell ChartDirector where are your data points by using Layer.setXData or Layer.setXData2.
Note that in your current code, the x-axis labels are just "names". They have no meaning (they are not the x-coordinates) and are for human reading only. You may use
"A", "B", "Apple", "Low", "Middle", "High" as the x-axis labels, and the chart would still work the same way. So in your current code, even with the x-axis labels, the leftmost x-coordinate is still 0. The x-coordinate simply reflect your array index.
As you cannot change the first array index (the first array index is always 0 in C++, and I cannot see why one need to change the first array index based on data value), so with your current code, the x-coordinate of the first data value in the array is always 0, as the array index is 0.
So I am thinking, if you need to change "the very left x-axis' value each time I read a new data", do you just mean you need to change the x-axis "label" (which is just a name). You can always change the names to anything you like by changing the contents of the m_HistoLabels array, but in C++, no matter what x-axis labels you use in the m_HistoLabels array, the first array index of m_HistoLabels is always 0.
If you need to use real data values as the x-coordinates (as opposed to just using the array index), you may use Layer.setXData and Layer.setXData2 to tell ChartDirector the x-coordinates of your data points. Note that the Axis.setLinearScale must also be configured to be consistent with your x-coordinates. For example, if the x-coordinates of your data points are from 8 to 13, but your x-axis is configured to be 0 to 10, then only the part of your data from 8 to 10 will be visible within the chart.
Hope this can help.
Regards
Peter Kwan |
Re: [MFC]starting point of x-axis |
Posted by Kaiden on Sep-30-2013 21:57 |
|
Hi Peter,
[If you need to use real data values as the x-coordinates (as opposed to just using the
array index)]
This was what I was looking for! I tried to follow your suggestions. Still encountered
some
problems.
If you take a look at [pic 1],
the first histogram(bar) is suppose to start at "-1.64" point but in the picture it starts off
at "-1.7" or lower.
I tried few different things with it and from that I am assuming the x-coordinates are not
set as real data values.
one curious thing is, I do have size for my histogram. For [pic 1], the sizes should be
pdCount[0] = 23
pdCount[1] = 11
pdCount[2] = 0
pdCount[3] = 0
pdCount[4] = 0
pdCount[5] = 0
pdCount[6] = 0
pdCount[7] = 28
*but how would chartdirector know where to start the pdCount??
the range is from LSL to USL so there's plenty of space.
How would chartdirect know the width of it(currently some bars are thicker than the
others)
=> the bar layer only is drawn around the center only where it is currently drawn at
[pic1].
[pic2] is from one of your customers, I want to make something almost the same as
[pic2]. Actually, I want it exactly the same. Just the histogram itself and the vertical
lines.
I need to put vertical line for LSL and USL AVG and things like this. but at the moment I
can't place the vline in the proper position because xaxis is not set as the real data
values.
How would I be able to place the histograms(bar layer) in the place where I want it to
be?? Thanks always.
Best Regards,
Kaiden.
///////////////// drawChart() fuction.
int arrFoundSize = arrFindVec.GetSize();
int nTotalRowCount = m_pDoc->iTotalRowCount;
dTitle = new double*[nTotalRowCount];
arrTempData.SetSize(nTotalRowCount); //
m_labels = new char*[arrFoundSize];
CString strTmpLabels;
strTmpLabels = _T("");
double USL= _wtof(m_pDoc->vec2dStr[2][arrFindVec.GetAt(0)]);
double LSL= _wtof(m_pDoc->vec2dStr[3][arrFindVec.GetAt(0)]);
double max=0.0;//0912 HY max from selected item
double min=0.0;//0912 HY min from selected item
//**default is 10 scale, but later on selectable from the user.
int nSelectResolution = 0;
int nScale = 0;
CComboBox* pComboResolution =
(CComboBox*)GetDlgItem(IDC_COMBO_RESOLUTION);
ASSERT(pComboResolution != NULL);
nSelectResolution = pComboResolution->GetCurSel();
nScale = m_aryTableResolution.GetAt(nSelectResolution);
//**get Max & Get Min
for(int i=0; i< nTotalRowCount; i++)
{
if(i==0)
{
max = _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]);
min = _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]);
}
else if( max < _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]))
max = _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]);
else if(min > _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]))
min = _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]);
}
//**get Max & Get Min
//**how many parts away from each xaxis.
double distance = 0.0;
distance = (max - min) / (nScale+1) ;
double* pRange;
int* pCount;
double* pdCount;
pRange = new double[nScale+1];
pCount = new int[nScale];
pdCount = new double[nScale+1];
for(int i=0; i< nScale; i++)
pCount[i] = 0;
//**labeling
pRange[0] = min;
for(int i=1; i< (nScale+1) ; i++)
pRange[i] = pRange[i-1] + distance;
pRange[nScale]= max;
double range= USL-LSL;
/*
for(int index=0; index< (nScale+2) ; index++)
{
if(index=0)
pRange[index] = LSL;
else if(index == nScale+1)
pRange[index] = USL;
else
pRange[index] = pRange[index-1] + distance;
}*/
//**labeling
//**************STANDARD DEVIATION / MEAN / VARIANCE START**************
//**************STANDARD DEVIATION / MEAN / VARIANCE START**************
//1.MEAN 평균
double dMean = 0;// move it to header.
double dSum = 0;// move it to header.
for(int i=0; i<nTotalRowCount; i++)
dSum += _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]);
dMean = dSum/nTotalRowCount;
//2. VARIANCE 분산
double dTemp = 0;
double dVariance = 0; // move it to header.
for(int i=0; i< nTotalRowCount; i++)
dTemp += (_wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]) -
dMean) * (_wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]) - dMean);
dVariance = dTemp/(nTotalRowCount);
//3. STANDARD DEVIATION 표준편차
double dStdDev = sqrt(dVariance);
//4. CP
double dCp = 0;
dCp = (USL-LSL)/(6*dStdDev);
double dCpu = 0;
double dCpl = 0;
double dCpk = 0;
dCpu = (USL - dMean)/(3*dStdDev);
dCpl = (dMean - LSL)/(3*dStdDev);
if(dCpu>dCpl)
dCpk = dCpl;
else
dCpk = dCpu;
//**********STANDARD DEVIATION / MEAN / VARIANCE END************
CString cpkString;
cpkString.Format(_T("MEAN: %.3lf VARIANCE: %.3lf STDDEV: %.3lf CP: %.3lf
Cpu: %.3lf Cpl: %.3lf CPK: %.3lf "), dMean, dVariance, dStdDev, dCp, dCpu, dCpl,
dCpk);
AfxMessageBox(cpkString);
//////////////////////////////////////////////////
for(int i=0; i< nTotalRowCount; i++)
{
double check = 0;
check = _wtof(m_pDoc->vec2dStr[i+5][arrFindVec.GetAt(0)]);
for(int j=0; j< (nScale+1); j++)
{
if( pRange[j] < check)
{
if( check < pRange[j+1])
{
pCount[j]++;
break;
}
}
}
}
for(int i=0; i< nScale+1; i++)
{
pdCount[i] = (double)pCount[i];
}
//------------------------------------------------------------------------
--------------------------------------
m_pChart = new XYChart(800, 600, 0xf0f0f0, 0xaaaaaa);
m_pChart->setPlotArea(75, 70, m_pChart->getWidth() - 90, m_pChart-
>getHeight() - 150, Chart::Transparent, -1, Chart::Transparent, 0x7F7F7F,
Chart::Transparent);
//**
m_pChart->addLegend(30, 20, false, "arialbd.ttf", 9)-
>setBackground(Chart::Transparent);
// As the data can lie outside the plotarea in a zoomed chart, we need
enable clipping.
m_pChart->setClipping();
//***
// Set the visible x-axis label range
/*
m_chartView.setFullRange("x", 0, nScale-1);
double startLabelIndex = m_chartView.getValueAtViewPort("x",
m_chartView.getViewPortLeft());
double endLabelIndex = m_chartView.getValueAtViewPort("x",
m_chartView.getViewPortLeft() + m_chartView.getViewPortWidth());
m_pChart->xAxis()->setLinearScale(startLabelIndex, endLabelIndex,
Chart::NoValue);
m_pChart->xAxis()->setLabelStyle("arialbd.ttf", 7, 0x008000)-
>setFontAngle(45);
// Add the labels with the range
for (int i = (int)ceil(startLabelIndex); i <= endLabelIndex; i++)
{
m_pChart->xAxis()->addLabel(i, m_HistoLabels[i]);
}
m_pChart->xAxis()->setLinearScale(startLabelIndex, endLabelIndex,
Chart::NoValue);
*/
// Set legend icon style to use line style icon, sized for 8pt font
m_pChart->getLegend()->setLineStyleKey();
m_pChart->getLegend()->setFontSize(8);
//m_pChart->yAxis()->setMinTickInc(1);
// Set the axis stem to transparent
m_pChart->xAxis()->setColors(Chart::Transparent);
m_pChart->yAxis()->setColors(Chart::Transparent);
m_pChart->xAxis()->setLabelStyle()->setFontAngle(55);
char* m_Title;
int strTitleLen = m_strTitle.GetLength();
m_Title = new char[strTitleLen+1];
WideCharToMultiByte(CP_ACP, 0,m_strTitle, -1, m_Title, strTitleLen+1, NULL,
NULL);
m_pChart->addTitle(m_Title, "ariali.ttf", 14);
//**
// Display 1 out of 3 labels on the x-axis.
//m_pChart->xAxis()->setLabelStep(1); //
//**
//m_nMouseMove = 0 ; //reset again.
BarLayer* layer = m_pChart->addBarLayer(Chart::Side, 1);
layer->addDataSet(DoubleArray(pdCount, nScale), m_pColorTable-
>aryListBoxTableColor.GetAt(1));
layer->setBarGap(Chart::TouchBar);
layer->setXData(min, max);
DrawArea *d = m_pChart->initDynamicLayer();
// The plot area object
PlotArea *plotArea = m_pChart->getPlotArea();
// Draw a vertical line and a horizontal line as the cross hair
d->vline(plotArea->getTopY(), plotArea->getBottomY(), -1.0, 0x0101);
//PETER, this vline doesn't work.
//d->removeDynamicLayer();
m_pChart->xAxis()->setLinearScale(LSL, USL, 0, 5);
//m_chartView.syncLinearAxisWithViewPort("x", m_pChart->xAxis());
m_chartView.syncLinearAxisWithViewPort("y", m_pChart->yAxis());
m_chartView.setScrollDirection(Chart::DirectionHorizontalVertical);
m_chartView.setZoomDirection(Chart::DirectionHorizontalVertical);
///////////////////////////////////////////////////////////////////////////////////////
// Output the chart
//////////////////////////////////////////////////////////////////////////////////////
// delete m_chartView.getChart();
d->vline(plotArea->getTopY(), plotArea->getBottomY(), LSL, d-
>dashLineColor(0x000000, 0x0000));
m_chartView.setChart(m_pChart);
delete[] pRange;
delete[] pCount;
|
Re: [MFC]starting point of x-axis |
Posted by Peter Kwan on Sep-30-2013 23:41 |
|
Hi Kaiden,
Normally, for bar charts, it is better to use the array index as the x-coordinates, not the values you see on the x-axis labels. If you use values as the x-coordinates, ChartDirector cannot assume evenly spaced bars, as your can always use x values that are not evenly spaced. Therefore, because the x values can be randomly spaced, so the bar spacing is not a fixed value, and ChartDirector will have to "guess" the bar width. The bar width may or may not be what you expect.
Anyway, for your case, the leading and empty space on the x-axis is caused by axis indention (see Axis.setIndent). It is caused by ChartDirector having to reserve some space for the bar width. You can disable axis indentation by using:
m_pChart->xAxis()->setIndent(false);
For the "chart 2" in your message, if I were to draw it myself, I would probably use a label based x-axis (use the array index as the x-coordinate, not the label value).
For the d->vline drawn on the dynamic layer, not that it should be drawn after the chart is drawn and displayed. Otherwise, it will be drawn behind the chart and covered by the chart, so you would not see it.
Hope this can help.
Regards
Peter Kwan |
Re: [MFC]starting point of x-axis |
Posted by Kaiden on Oct-01-2013 08:12 |
|
Hi Peter,
Thanks, I understand what to do now(haven't tried it yet).
Say I drew the bar graph using xaxis as an array.
then, how can I place the vlines in the positions where I would want it to be placed? just
like in the pic2. |
Re: [MFC]starting point of x-axis |
Posted by Kaiden on Oct-01-2013 22:25 |
|
Hi Peter,
What I did so far was,
1. get my range or scale of xAxis then, I split it into 200 sections.
distance = (USL - LSL) / (nScale) ;
2. I would start labeling it
for(int i=0; i< (nScale+1) ; i++)
label[i] = label[i-1] + distance;
3. Draw the chart. l
l ll
lll lll ll
-----------------------lllllllllllll--------------------------------
-5 -1.6 5
It looks something like this at the moment.
the labels is array[201].
How can I place the vertical line on the right position?
1. LSL, USL vertical line.
2. Cpk line
2. Avg line
things like these..so it would look something like [pic1]
|
Re: [MFC]starting point of x-axis |
Posted by Kaiden on Oct-01-2013 22:36 |
|
Hi Peter,
I know I am asking alot of questions. I am really sorry bout that. But I gotta finish this off:)
on the previous question, I told you that I did something like
distance = (USL - LSL) / (nScale) ; nScale=200
If I draw label every step, there would be 200 labels and that's way too much.
If I set labelstep(10).
looks good at first, but when I zoom in alot, I only see like two~ three labels only.
Is it possible to leave at least 10 labels in xAxis all the time?
As I zoom in or zoom out, ofcourse the labelings will change in to whatever position i am
zooming into. but keep 10 number of labels on the chart all the time.
Would it be possible?
Thanks,
Best Reagrds,
Kaiden. |
Re: [MFC]starting point of x-axis |
Posted by Peter Kwan on Oct-02-2013 02:12 |
|
Hi Kaiden,
Your array index is from 0 to nScale, and your labels are from LSL to USL. So for a label value at x, the index must be at:
double indexPos = (x - LSL) / distance;
To draw the vertical liine, you can use Axis.addMark:
Mark *m = c->xAxis()->addMark(indexPos, 0xff0000, "ABC", "arialbd.ttf", 10);
m->setLineWidth(3);
m->setAlignment(Chart::TopCenter);
Hope this can help.
Regards
Peter Kwan |
Re: [MFC]starting point of x-axis |
Posted by Kaiden on Oct-02-2013 18:13 |
|
Hi Peter,
Thanks!!! It's working fine!! You really are the man!!
Best Regards,
Kaiden |
Re: [MFC]starting point of x-axis |
Posted by Peter Kwan on Oct-02-2013 02:25 |
|
Hi Kaiden,
Your current scale is from -5 to 5 and there are 200 sections. So the distance between the section is 0.05.
Suppose you zoom in 100X. You may see only 2 or 3 labels (even without using label step). So you cannot display 10 labels because you only have 2 or 3 labels at this zoom level, even if you do not use setLabelStep.
If you zoom in by 20X, you may see 11 labels even if you do not use setLabelStep. Again, you cannot display 10 regular labels, because it shows 11 labels if there is no setLabelStep, and it will show 5 or 6 labels if you use setLabelStep(2).
Even without zooming and without the original 201 labels, no matter what label step you use, you cannot get exactly 10 labels visible on the x-axis. (If you use setLabelStep(20), there will be 11 labels visible.)
You can see in general, you may not get exactly 10 labels on the x-axis. You can only ensure a reasonable number of labels on the x-axis, but not an exact number.
To ensure a reasonable number of labels, just set the label step based on the zoom level. For your case, the number of labels visible before setLabelStep should be around:
double visibleLabels = myChartViewer->getViewPortWidth() * nScale;
Suppose you want to show as many labels as possible but no more than 20, the label step must be:
int labelStep = (int)ceil(visibleLabels / 20);
c->xAxis()->setLabelStep(labelStep);
Hope this can help.
Regards
Peter Kwan |
Re: [MFC]starting point of x-axis |
Posted by Kaiden on Oct-02-2013 18:14 |
|
Hi Peter,
I really do thank you a lot for helping out! Have a great day!!
Best Regards,
Kaiden. |
|