Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
118a8f10cf | ||
|
|
fa9656b653 | ||
|
|
160fea2c0c | ||
|
|
8b5451c5bd | ||
|
|
1c59e26722 | ||
|
|
c34c5eb51d | ||
|
|
c06c71b091 | ||
|
|
1ac5c428bd | ||
|
|
aefbc413a6 | ||
|
|
9d010c254c | ||
|
|
78853bd7be | ||
|
|
8bafc714c3 | ||
|
|
7d139093df |
4
0BUILD
4
0BUILD
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
<gwbuild requiredVersion="5.9.0" >
|
<gwbuild requiredVersion="5.9.0" >
|
||||||
|
|
||||||
<project name="aqdiagram" version="0.1.4"
|
<project name="aqdiagram" version="0.1.5"
|
||||||
so_current="0" so_age="0" so_revision="4"
|
so_current="0" so_age="0" so_revision="5"
|
||||||
write_config_h="TRUE"
|
write_config_h="TRUE"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|||||||
92
README.md
92
README.md
@@ -24,8 +24,98 @@ gwbuild -jNN (with NN number of parallel processes, e.g. 4 for quadcore cpu)
|
|||||||
sudo gwbuild -i
|
sudo gwbuild -i
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Structure of AqDiagram
|
||||||
|
|
||||||
|
AqDiagram consists of 4 parts:
|
||||||
|
- __data__:
|
||||||
|
Library for data manipulation (accumulate, negate, diff, average, floating average, sums for days and months)
|
||||||
|
- __draw__:
|
||||||
|
Library for drawing text and simple figures (points, lines, rectangles), current implementation for libcairo).
|
||||||
|
- __placement__:
|
||||||
|
Library for placement of objects in a plane.
|
||||||
|
- __graph__:
|
||||||
|
Library for drawing graphs using the other libraries.
|
||||||
|
|
||||||
|
|
||||||
## Code Examples
|
## Code Examples
|
||||||
|
|
||||||
https://gitea.aqbanking.de/martin/aqdiagram/src/branch/master/src/lib/aqdiagram/libtest.c
|
### Simple Graph with a Single Curve
|
||||||
|
|
||||||
|
```
|
||||||
|
AQDG_GRAPH *g;
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
AQDG_DRAW_CONTEXT *dc;
|
||||||
|
AQDG_OBJECT *graphObject;
|
||||||
|
|
||||||
|
g=AQDG_TimeGraph_new("Title", "Subtitle", "Value", "mm", 0);
|
||||||
|
|
||||||
|
/* get data to be shown (insert your function here) */
|
||||||
|
dpList=CREATE_DATA_FOR_GRAPH();
|
||||||
|
|
||||||
|
/* add single curve as line graph */
|
||||||
|
AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_LINE, dpList);
|
||||||
|
|
||||||
|
/* setup ticks for X and Y axis (use auto-calculated upper and lower limit) */
|
||||||
|
AQDG_TimeGraph_SetupTicks(g, 0, 0.0, 0.0);
|
||||||
|
|
||||||
|
/* draw graph as PNG file (here with 800x600 pixels) */
|
||||||
|
dc=AQDG_Draw_ContextCairo_Png_new("/tmp/testgraph.png", 800, 600);
|
||||||
|
graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, dc);
|
||||||
|
AQDG_Object_SetWidth(graphObject, 800);
|
||||||
|
AQDG_Object_SetHeight(graphObject, 600);
|
||||||
|
|
||||||
|
/* use default pens and fonts */
|
||||||
|
AQDG_GraphWidget_SetupDefaultPens(graphObject);
|
||||||
|
AQDG_GraphWidget_SetupDefaultFonts(graphObject);
|
||||||
|
|
||||||
|
/* finish creating the PNG file */
|
||||||
|
AQDG_GraphWidget_FinishWithGraph(graphObject, g);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Graph with a Bar Graph and a Derived Line Curve
|
||||||
|
|
||||||
|
```
|
||||||
|
AQDG_GRAPH *g;
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *dpList;
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *derivedDpList;
|
||||||
|
AQDG_DRAW_CONTEXT *dc;
|
||||||
|
AQDG_OBJECT *graphObject;
|
||||||
|
|
||||||
|
g=AQDG_TimeGraph_new("Title", "Subtitle", "Value", "mm", 0);
|
||||||
|
|
||||||
|
/* get data to be shown (insert your function here) */
|
||||||
|
dpList=CREATE_DATA_FOR_GRAPH();
|
||||||
|
|
||||||
|
/* add first curve as bar graph */
|
||||||
|
AQDG_TimeGraph_AddCurve(g, "Testdata", AQDG_GRAPH_TYPE_BARS, dpList);
|
||||||
|
|
||||||
|
/* use a data modification function on initial data (here: accumulate) */
|
||||||
|
derivedDpList=AQDG_Data_Accumulate(dpList);
|
||||||
|
|
||||||
|
/* add 2nd curve with accumulated data as line graph */
|
||||||
|
AQDG_TimeGraph_AddCurve(g, "Accumulated", AQDG_GRAPH_TYPE_LINE, derivedDpList);
|
||||||
|
|
||||||
|
/* setup ticks for X and Y axis (use auto-calculated upper and lower limit) */
|
||||||
|
AQDG_TimeGraph_SetupTicks(g, 0, 0.0, 0.0);
|
||||||
|
|
||||||
|
/* draw graph as PNG file (here with 800x600 pixels) */
|
||||||
|
dc=AQDG_Draw_ContextCairo_Png_new("/tmp/testgraph.png", 800, 600);
|
||||||
|
graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, dc);
|
||||||
|
AQDG_Object_SetWidth(graphObject, 800);
|
||||||
|
AQDG_Object_SetHeight(graphObject, 600);
|
||||||
|
|
||||||
|
/* use default pens and fonts */
|
||||||
|
AQDG_GraphWidget_SetupDefaultPens(graphObject);
|
||||||
|
AQDG_GraphWidget_SetupDefaultFonts(graphObject);
|
||||||
|
|
||||||
|
/* finish creating the PNG file */
|
||||||
|
AQDG_GraphWidget_FinishWithGraph(graphObject, g);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -84,3 +84,33 @@ double AQDG_Data_GetAbsMinDiffY(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DifferenceY(const AQDG_GRAPH_DATAPAIR_LIST *dpList)
|
||||||
|
{
|
||||||
|
if (dpList && AQDG_Graph_DataPair_List_GetCount(dpList)) {
|
||||||
|
AQDG_GRAPH_DATAPAIR_LIST *newList;
|
||||||
|
const AQDG_GRAPH_DATAPAIR *dp;
|
||||||
|
|
||||||
|
newList=AQDG_Graph_DataPair_List_new();
|
||||||
|
dp=AQDG_Graph_DataPair_List_First(dpList);
|
||||||
|
if (dp) {
|
||||||
|
double lastValue;
|
||||||
|
|
||||||
|
lastValue=AQDG_Graph_DataPair_GetValueY(dp);
|
||||||
|
while(dp) {
|
||||||
|
AQDG_GRAPH_DATAPAIR *newDp;
|
||||||
|
double v;
|
||||||
|
|
||||||
|
v=AQDG_Graph_DataPair_GetValueY(dp);
|
||||||
|
newDp=AQDG_Graph_DataPair_dup(dp);
|
||||||
|
AQDG_Graph_DataPair_SetValueY(newDp, v-lastValue);
|
||||||
|
AQDG_Graph_DataPair_List_Add(newDp, newList);
|
||||||
|
lastValue=v;
|
||||||
|
dp=AQDG_Graph_DataPair_List_Next(dp);
|
||||||
|
}
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
AQDG_API double AQDG_Data_GetAbsMinDiffX(const AQDG_GRAPH_DATAPAIR_LIST *dpList);
|
AQDG_API double AQDG_Data_GetAbsMinDiffX(const AQDG_GRAPH_DATAPAIR_LIST *dpList);
|
||||||
|
AQDG_API double AQDG_Data_GetAbsMinDiffY(const AQDG_GRAPH_DATAPAIR_LIST *dpList);
|
||||||
|
|
||||||
|
AQDG_API AQDG_GRAPH_DATAPAIR_LIST *AQDG_Data_DifferenceY(const AQDG_GRAPH_DATAPAIR_LIST *dpList);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Previous af_graphics
|
|
||||||
@@ -52,6 +52,94 @@
|
|||||||
</content>
|
</content>
|
||||||
</inline>
|
</inline>
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
static int _genLog10TicksUp($(struct_type) *st, \n
|
||||||
|
double vStart, \n
|
||||||
|
double vStep, \n
|
||||||
|
double vBegin, double vEnd, \n
|
||||||
|
int level, \n
|
||||||
|
int precision) \n
|
||||||
|
{ \n
|
||||||
|
double vRun; \n
|
||||||
|
GWEN_BUFFER *dbuf; \n
|
||||||
|
\n
|
||||||
|
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
|
||||||
|
vRun=vStart; \n
|
||||||
|
while(vRun<=vEnd) { \n
|
||||||
|
if (vRun>=vBegin) { \n
|
||||||
|
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
|
||||||
|
GWEN_Buffer_AppendArgs(dbuf, "%.*f", precision, vRun); \n
|
||||||
|
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, level, 0, vStep); \n
|
||||||
|
DBG_INFO(NULL, "Adding tick %d: %s", level, GWEN_Buffer_GetStart(dbuf)); \n
|
||||||
|
GWEN_Buffer_Reset(dbuf); \n
|
||||||
|
} \n
|
||||||
|
} \n
|
||||||
|
vRun+=vStep; \n
|
||||||
|
} \n
|
||||||
|
GWEN_Buffer_free(dbuf); \n
|
||||||
|
return ($(struct_prefix)_HasAtLeastNLevelTicks(st, level, level?2:4))?1:0; \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
static int _genLog10TicksDown($(struct_type) *st, \n
|
||||||
|
double vStart, \n
|
||||||
|
double vStep, \n
|
||||||
|
double vBegin, double vEnd, \n
|
||||||
|
int level, \n
|
||||||
|
int precision) \n
|
||||||
|
{ \n
|
||||||
|
double vRun; \n
|
||||||
|
GWEN_BUFFER *dbuf; \n
|
||||||
|
\n
|
||||||
|
dbuf=GWEN_Buffer_new(0, 256, 0, 1); \n
|
||||||
|
vRun=vStart; \n
|
||||||
|
while(vRun>=vEnd) { \n
|
||||||
|
if (vRun<=vBegin) { \n
|
||||||
|
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
|
||||||
|
GWEN_Buffer_AppendArgs(dbuf, "%.*f", precision, vRun); \n
|
||||||
|
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, level, 0, vStep); \n
|
||||||
|
DBG_INFO(NULL, "Adding tick %d: %s", level, GWEN_Buffer_GetStart(dbuf)); \n
|
||||||
|
GWEN_Buffer_Reset(dbuf); \n
|
||||||
|
} \n
|
||||||
|
} \n
|
||||||
|
vRun-=vStep; \n
|
||||||
|
} \n
|
||||||
|
GWEN_Buffer_free(dbuf); \n
|
||||||
|
return ($(struct_prefix)_HasAtLeastNLevelTicks(st, level, level?2:4))?1:0; \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
|
<inline loc="code">
|
||||||
|
<content>
|
||||||
|
static int _genLog10Ticks($(struct_type) *st, \n
|
||||||
|
double vStart, \n
|
||||||
|
double vStep, \n
|
||||||
|
double vMin, double vMax, \n
|
||||||
|
int level, \n
|
||||||
|
int precision) \n
|
||||||
|
{ \n
|
||||||
|
if (vMin<0.0 && vMax>=0.0) { \n
|
||||||
|
int rv; \n
|
||||||
|
\n
|
||||||
|
rv=_genLog10TicksUp(st, 0.0, vStep, 0.0, vMax, level, precision); \n
|
||||||
|
rv|=_genLog10TicksDown(st, 0.0, vStep, 0.0, vMin, level, precision); \n
|
||||||
|
return rv; \n
|
||||||
|
} \n
|
||||||
|
else if (vMin<0.0 && vMax<=0.0) \n
|
||||||
|
return _genLog10TicksDown(st, vStart, vStep, vMax, vMin, level, precision); \n
|
||||||
|
else \n
|
||||||
|
return _genLog10TicksUp(st, vStart, vStep, vMin, vMax, level, precision); \n
|
||||||
|
} \n
|
||||||
|
</content>
|
||||||
|
</inline>
|
||||||
|
|
||||||
|
|
||||||
<inline loc="end" access="public">
|
<inline loc="end" access="public">
|
||||||
<content>
|
<content>
|
||||||
@@ -65,68 +153,48 @@
|
|||||||
{ \n
|
{ \n
|
||||||
double absMaxValue; \n
|
double absMaxValue; \n
|
||||||
double v; \n
|
double v; \n
|
||||||
double vRun; \n
|
double vMin; \n
|
||||||
double startValue; \n
|
double vMax; \n
|
||||||
GWEN_BUFFER *dbuf; \n
|
double vStart; \n
|
||||||
int nextLevel=0; \n
|
int nextLevel=0; \n
|
||||||
\n
|
\n
|
||||||
absMaxValue=abs(st->minValue); \n
|
vMin=st->minValue; \n
|
||||||
v=abs(st->maxValue); \n
|
vMax=st->maxValue; \n
|
||||||
|
absMaxValue=abs(vMin); \n
|
||||||
|
v=abs(vMax); \n
|
||||||
absMaxValue=(v>absMaxValue)?v:absMaxValue; \n
|
absMaxValue=(v>absMaxValue)?v:absMaxValue; \n
|
||||||
\n
|
\n
|
||||||
dbuf=GWEN_Buffer_new(0, 64, 0, 1); \n
|
|
||||||
if (absMaxValue==0.0) \n
|
if (absMaxValue==0.0) \n
|
||||||
absMaxValue=1.0; \n
|
absMaxValue=1.0; \n
|
||||||
v=pow(10, floor(log10(absMaxValue))); \n
|
v=pow(10, floor(log10(absMaxValue))); \n
|
||||||
\n
|
\n
|
||||||
startValue=v; \n
|
vStart=v; \n
|
||||||
if ((st->minValue)<startValue) \n
|
if (vMin<vStart) \n
|
||||||
startValue=-startValue; \n
|
vStart=-vStart; \n
|
||||||
|
\n
|
||||||
|
for(;;) { \n
|
||||||
|
int rv; \n
|
||||||
\n
|
\n
|
||||||
while(v>=0.0) { \n
|
|
||||||
DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
|
DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
|
||||||
if (nextLevel>=3) \n
|
if (nextLevel>=3) \n
|
||||||
break; \n
|
break; \n
|
||||||
vRun=startValue; \n
|
rv=_genLog10Ticks(st, vStart, v, vMin, vMax, nextLevel, st->precision); \n
|
||||||
while(vRun<=(st->maxValue)) { \n
|
if (rv) \n
|
||||||
if (vRun>=(st->minValue)) { \n
|
nextLevel++; \n
|
||||||
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
|
else \n
|
||||||
GWEN_Buffer_AppendArgs(dbuf, "%.*f", st->precision, vRun); \n
|
$(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
|
||||||
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, nextLevel, 0, v); \n
|
|
||||||
DBG_INFO(NULL, "Adding tick %d: %s", nextLevel, GWEN_Buffer_GetStart(dbuf)); \n
|
|
||||||
GWEN_Buffer_Reset(dbuf); \n
|
|
||||||
} \n
|
|
||||||
} \n
|
|
||||||
vRun+=v; \n
|
|
||||||
} \n
|
|
||||||
v/=2.0; \n
|
v/=2.0; \n
|
||||||
if ($(struct_prefix)_HasAtLeastNLevelTicks(st, nextLevel, nextLevel?1:4)) \n
|
|
||||||
nextLevel++; \n
|
|
||||||
else \n
|
|
||||||
$(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
|
|
||||||
\n
|
\n
|
||||||
DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
|
|
||||||
if (nextLevel>=3) \n
|
if (nextLevel>=3) \n
|
||||||
break; \n
|
break; \n
|
||||||
vRun=startValue; \n
|
DBG_INFO(NULL, "Handling level %d (%.2f)", nextLevel, v); \n
|
||||||
while(vRun<=(st->maxValue)) { \n
|
rv=_genLog10Ticks(st, vStart, v, vMin, vMax, nextLevel, st->precision); \n
|
||||||
if (vRun>=(st->minValue)) { \n
|
if (rv) \n
|
||||||
if (!$(struct_prefix)_HasTickValue(st, vRun)) { \n
|
|
||||||
GWEN_Buffer_AppendArgs(dbuf, "%.*f", st->precision, vRun); \n
|
|
||||||
$(struct_prefix)_AddNewTick(st, GWEN_Buffer_GetStart(dbuf), vRun, nextLevel, 0, v); \n
|
|
||||||
DBG_INFO(NULL, "Adding tick %d: %s", nextLevel, GWEN_Buffer_GetStart(dbuf)); \n
|
|
||||||
GWEN_Buffer_Reset(dbuf); \n
|
|
||||||
} \n
|
|
||||||
} \n
|
|
||||||
vRun+=v; \n
|
|
||||||
} \n
|
|
||||||
v/=5.0; \n
|
|
||||||
if ($(struct_prefix)_HasAtLeastNLevelTicks(st, nextLevel, nextLevel?1:4)) \n
|
|
||||||
nextLevel++; \n
|
nextLevel++; \n
|
||||||
else \n
|
else \n
|
||||||
$(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
|
$(struct_prefix)_RemoveLevelTicks(st, nextLevel); \n
|
||||||
} /* while */ \n
|
v/=5.0; \n
|
||||||
GWEN_Buffer_free(dbuf); \n
|
} /* for */ \n
|
||||||
} \n
|
} \n
|
||||||
</content>
|
</content>
|
||||||
</inline>
|
</inline>
|
||||||
|
|||||||
Reference in New Issue
Block a user