From 604f59fd0d2e863c59f56c24cfefcc5f65251fdd Mon Sep 17 00:00:00 2001 From: jkriege2 Date: Sun, 2 Aug 2015 15:04:37 +0200 Subject: [PATCH] added barchart example (+minor improvements) --- README.md | 95 +++++++++++++++++- jkqtpbaseelements.h | 36 ++++++- jkqtpbaseplotter.h | 6 +- jkqtpelements.h | 3 + .../jkqtplotter_simpletest_barchart.png | Bin 0 -> 30503 bytes .../jkqtplotter_simpletest_barchart.cpp | 84 ++++++++++++++++ .../jkqtplotter_simpletest_barchart.pro | 16 +++ 7 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 screenshots/jkqtplotter_simpletest_barchart.png create mode 100644 test/jkqtplotter_simpletest_barchart/jkqtplotter_simpletest_barchart.cpp create mode 100644 test/jkqtplotter_simpletest_barchart/jkqtplotter_simpletest_barchart.pro diff --git a/README.md b/README.md index 19a51ed71e..e7324f8706 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ int main(int argc, char* argv[]) The result looks like this: ![jkqtplotter_simpletest1](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest1.png) -###Very simple line-graph +###Simple line-graph with error bars This project (see `./test/jkqtplotter_simpletest_symbols_and_errors/`) simply creates a JKQtPlotter widget (as a new window) and adds a single line-graph (a sine-wave) that has y-errorbars. In addition, this example shows how to change some of the axis properties and how to use LaTeX markup to format axis labels (can actually be used for all labels in JKQtPlotter). Also, in comparison to the last example, here we initialize the data from C-type arrays (double*), instead of QVector objects. The soruce code of the main application is (see `./test/jkqtplotter_simpletest_symbols_and_errors/jkqtplotter_simpletest_symbols_and_errors.cpp`): @@ -156,6 +156,99 @@ int main(int argc, char* argv[]) The result looks like this: ![jkqtplotter_simpletest_symbols_and_errors](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_symbols_and_errors.png) +###Simple barchart +This project (see `./test/jkqtplotter_simpletest_barchart/`) simply creates a JKQtPlotter widget (as a new window) and adds a single line-graph (a sine-wave) that has y-errorbars. In addition, this example shows how to change some of the axis properties and how to use LaTeX markup to format axis labels (can actually be used for all labels in JKQtPlotter). Also, in comparison to the last example, here we initialize the data from C-type arrays (double*), instead of QVector objects. + +The soruce code of the main application is (see `./test/jkqtplotter_simpletest_barchart/jkqtplotter_simpletest_barchart.cpp`): +```c++ +#include +#include "jkqtplotter.h" + +#define Ndata 5 +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + // 1. create a plotter window and get a pointer to the internal datastore (for convenience) + JKQtPlotter plot; + plot.get_plotter()->set_useAntiAliasingForGraphs(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForSystem(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForText(true); // nicer (but slower) text rendering + JKQTPdatastore* ds=plot.getDatastore(); + + // 2. now we create data for three simple barchart + QString L[Ndata]={ "cat. A", "cat. B", "cat. C", "cat. D", "other"}; + double X[Ndata]={ 1, 2, 3, 4, 5}; + double Y1[Ndata]={ 5, 4, 3, 4, 5}; + double Y2[Ndata]={ -5, -3, 1, 3, 6}; + double Y3[Ndata]={ 6, 2, 5, 3, 6}; + + // 3. make data available to JKQtPlotter by adding it to the internal datastore. + // Note: In this step the data is copied (of not specified otherwise) + // the variables columnX and columnY... will contain the internal column ID of the + // newly created columns with names "x" and "y..." and the (copied) data from X + // and Y... + size_t columnX=ds->addCopiedColumn(X, Ndata, "x"); + size_t columnY1=ds->addCopiedColumn(Y1, Ndata, "y1"); + size_t columnY2=ds->addCopiedColumn(Y2, Ndata, "y2"); + size_t columnY3=ds->addCopiedColumn(Y3, Ndata, "y3"); + + // 4. create graphs in the plot, which plots the dataset X/Y1, X/Y2 and X/Y3: + JKQTPbarHorizontalGraph* graph1=new JKQTPbarHorizontalGraph(&plot); + graph1->set_xColumn(columnX); + graph1->set_yColumn(columnY1); + graph1->set_title(QObject::tr("dataset 1")); + JKQTPbarHorizontalGraph* graph2=new JKQTPbarHorizontalGraph(&plot); + graph2->set_xColumn(columnX); + graph2->set_yColumn(columnY2); + graph2->set_title(QObject::tr("dataset 2")); + JKQTPbarHorizontalGraph* graph3=new JKQTPbarHorizontalGraph(&plot); + graph3->set_xColumn(columnX); + graph3->set_yColumn(columnY3); + graph3->set_title(QObject::tr("dataset 3")); + + + // 5. add the graphs to the plot, so it is actually displayed + plot.addGraph(graph1); + plot.addGraph(graph2); + plot.addGraph(graph3); + + // 6. now we set the graphs, so they are plotted side-by-side + // This function searches all JKQTPbarHorizontalGraph in the current + // plot and sets their shift/scale so they form a nice plot with + // side-by-side groups + graph1->autoscaleBarWidthAndShift(0.75, 1); + + // 7. data is grouped into 5 numbere groups (1..5), but we also have string + // labels for these groups (stored in L). In order to display these labels, + // we have to tell the x-Axis to use these special labels: + plot.getXAxis()->addAxisTickLabels(X, L, Ndata); + // also we can rotate the labels a bit (by 45 degree), so they fit better + plot.getXAxis()->set_tickLabelAngle(45); + plot.getXAxis()->set_tickLabelFontSize(12); + + // 8. finally we move the plot key/legend to the outside, top-right + // and lay it out as a single row + // NOTE: plot is a descendent of QWidget, which uses an internal object of + // type JKQTBasePlotter, which does the actual plotting. + // So many properties of the plot are only available in this internal + // object, which you can access by plot.get_plotter(). + plot.get_plotter()->set_keyPosition(JKQTPkeyOutsideTopRight); + plot.get_plotter()->set_keyLayout(JKQTPkeyLayoutOneRow); + + // 9 autoscale the plot so the graph is contained + plot.zoomToFit(); + + // show plotter and make it a decent size + plot.show(); + plot.resize(600,400); + + return app.exec(); +} +``` +The result looks like this: +![jkqtplotter_simpletest_barchart](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_barchart.png) + ##Screenshots ###Scatter Plots and Boxplots diff --git a/jkqtpbaseelements.h b/jkqtpbaseelements.h index 632aa51334..f1b0434c5e 100644 --- a/jkqtpbaseelements.h +++ b/jkqtpbaseelements.h @@ -195,20 +195,50 @@ class LIB_EXPORT JKQTPcoordinateAxis: public QObject { } else { return xx/(scaleSign*scale); } - }; + } /** \brief clear axis tick labels. This switches back to automatic labels mode for the axis. */ inline void clearAxisTickLabels() { tickLabels.clear(); update_plot(); - }; + } /** \brief add a new tick label to the axis */ inline void addAxisTickLabel(double x, QString label) { tickLabels.append(qMakePair(x, label)); update_plot(); - }; + } + + + /** \brief add a new tick label to the axis */ + inline void addAxisTickLabels(const QVector& x, const QStringList& label) { + for (int i=0; i& x, const QString* label) { + for (int i=0; i3@8`@4s{J+{|P$=SlX?K2KTuIqR$wqN)Cd^da3tJUl#7WhHrSJiNPbJiI$~ zgb#3*ej#KS?&FS&_8VEeilJwlxC4A^5Ez7qR~1EkWqu!bO!QvK&;<|gQOCdcogT*` zE1Z$iRl&ej#}Vf0VeSmYd*cj+I=H|cT}|H-;)b|qD9eL%KbY>O6C^+Ds;#4;vbSrf ztGvEfx4(+AwG6mJkV7QI|1LW&3l^#^Gc z!+z>-C)L~>hj#`XcI_sI&ZLG*Q;PSdH#fJ6ecz5}v+}+1+4m#Ftp^WJSNfALbV#(# zgZcVbk4&Mv$puDY-|u%M*$v(BB}zs=dTQ9U&nv}K!cm&P%ZNag>UM#D10XlxMdAqi z6%mlB@TWl6Z--`q=x9qK6TXo6#`BtMx8}EV$HJ?H zi@?*ozXny4f7siGe!dBvuPmH?`=C-@?A>2YDp8HV^v3UgR3EuH9A?AG>m!nWTuJ|R zvbY&JbB1ZVIjQs?E%zFpI{cY6 zY)RIgc=??n$?WIJ5!tHolIhaBPm!Np#sp;YB26x_P3Z*1lPe5k-xg<_M|1p8YZFI_ z*OOZPceabhzn_FAme>Jmm#Qc32@k*bWQSO1J!#{QOuYAZKj~9TSxWF_WDv|}G7moE z=oZTEv+UV4%njZLMtC9UPK=A;Q!Z~q3;&+PN$DB%ZYPXoT|Vrhnoq=1nViRXUgfWb z_S|Lk5g6<+NgQS2-{?W6r|_w6W)G=8c9Q^P6Nncy-kx{4nh^}P3) zkq*MJC*TzJn$4y{Yiwn%uar`Bg6vjRU4<4-ry(adUV3!9{A9?*D{@|{ z11nfbL^`ZHwcT&OG9B1opFFebzMAmmX=}$jm&)+Wyb|dtT`U@$CWEh>@$@>LORk-f zfk~3(*C$gu+dR*AH42Dn5d=1pKkNg)?{;)Wsmx~2lK&>dwBp-`qlGbhN|!EOI@ryh zL3D`Ryz-`?7?B;E6N*K4FW74~9ylxprZ$wv)m7>d&r>g8ocZQ|?&kdAK=9|!ubdt| zLcB?7&M^6IUy80oHRli7R~C2JAGFLpTI`8BQ@tFBB6BrPTLL-seExEG%gq#Jf!#aX zh$7z;B8B#ths{V@#9PevYN37N*AldH5lI%0cZsKlpJ|3?i6)Dt)c>>q4)^rt zM#Q%W*u1(0n6tKY?^vG-c%_(xYN6w%DZZvBITG`)XFy9gH2jJ{vu4+?#gZD5UL`je zWI@F(>;=saG1pbh+SKO7hJ}neveeH7PX@A1#$fMJ)?dmB>*PcSi7iL(Tfptj@y8S=0@};SYJKlQdd1`2xMX{Q+f3B01ewv&W87y z-C>qj!RnGv6@$-W)7T5~lpj<=0c^Ak`xVCU&o#{0wS;2XZ$r=ugJ`X~qWPz2gi{W? zeRd)mUDW4?%#DS~4<-UxY-DxE@&@Y^>~jfc#3o17snMQ^X;8}AP!$v*BsUQO>et5v z8nc1%%V+O-U>Ahx5l7M4Ty=u8UmgZ*CS=ROX==Vqi>e*bxjg?BVNA<7e8+t1U6<{E zG>pIIi;NddP26<5-8yup+m2|e7A`hkQha}~A^u<3i#Whd6P*ion?DnZlKXNuxv02o zh2Zyyqk^eAqL}rDNoSQ9f*kYK-#Fx`=O)Lb79SN2jzN#9kuUt?yGF%=)UQOHvswHy zB6!~fQ>4VKM#{D7Jlp+p;PFUF)e7m8H(f-29(R&J-A+nzC*I9ABx9TkzLkfNq4@T( zmHC5t6;*bP*Oseedchsyd8&Cm%yNNsq=2mcZ5Q-mOv4um+buUtixY^fOE3~pcPlua*yu5@raytLu2EOSt&3yh#qC* zTA6-4QMDpG5wVrP>yqS@%M(!r{3*O;Yffbt7j$ixD2%xBwx^kjRD%8%G73rTRu zxvoEH4hVbUU`_NoJ7iYGGQ@6ubnz3wT0~2kM|I3jnWwTy!E0>CwAN0_rml$gpAjQv zvv~_wF=CC?ODsxRK)=$e@xtcB!opCSV4<8kr^)u{EZQ7@SQtbF6DavFm>}%>T@V!l z8>=_EfL8NA)lQ#9oRyrQTh08s*kM97Zm<1tA+t86efiOybVtK0+2>9r>6Qk;gqR-hK6DS)ZwI}6C`$FfG9n(R1 z4*7Kc;~ifys)ZDdRN2^$vVLtTx2SJfUkvY$%S|fe20`9hR_n$vItW+ykW#2-Afi|N zqWvkP0Y00zhyqR0RG>5O$2%Tq^UY;NO*#dkWA2Cz;khi+ad?o;hkQ`$-_c@M3eh=C zR_0|E@QUg~;mZs*`)B(=OsqSd3@TmA)jEOMp(pXv|E=l)r8$vd-JqhblOkF}T(qa9 zY-9@mar8QD%31kwTCZHmBe=fIA09=7p*QlolQMMdrrVeY(G! z#0#H2W5}cBIUOB%QW<2}2OTJTTbXE4XI=}7R4`8Y>N(u3+vX%Ob9?%xxVo|QtkAF~ z6H>Pi7F~phazGBg9Zj@S_fNF=WmkBN=jbPv7mQ0aVIi=Vks1km3lSkBFSo+oJI%-w z%^m3J!S?ll?ZBsxG;}~BpSo{D1`DZ+9XR~wLXI%PXohbe*08*zuVFLDAic}KC=Tl> zJ9k~azn(}5Jb30L=p^LUT`-X4J~E*OHFw{F3}K|iVNZ2V603lc!-vnEM?G~RKbva4 z1&5zxd<(cxn+9DMw5r`J*v-3x^}u|mtz7y1jf3XmXpuk6*Kni1AHE@!kTm{q$lTOV3=~Ml66g9U*xZPx9(Dg?oE%Q$S)q8vc(L#bCJCFoFtU+VrAz< zQe%4ezbB%NamZa;ltufKvbNd^EDzwdZDh)2U%}*3Po@?q0OnJ1$q<@H8=gn2CDej& zkAmoqEd@#Crwhfx@a?e`GT6Y+l_Q-B5>MiI+4+4HYFG#3*_t26(bx{yrWUJuBw2I} zc@!%14kt{Cs%0$?;p4{MgYhR^}G z72XTfiqd}fYBG`#;E%kEr-*MRXoZg@nEKu!oD>NR)zxQkWTDSmyHuq__&v(UiVI~ZHmU4U%ox@ z%yi-{bq(MhaZSj-tPqEh`rUBD*!Z#4@20J2MI$oh^>0tn+WzdpajUHG;ktbTzKm@t zEmG@H{9ba{u=1?#aO`nBsf8y+JB24*SB@~Uosq8jJyV3y6?epNj8ho&=9$4`MQING zZr-U>*+hY^s}G7$b5=hMIj&KwJ8zk}s^J~7MQj4(vRw`ekQ+=aO>7I|(++q%);cU> z9&6n>M8Z}2+agi?8Xm$hnZ4CwnJr{7sSsorU_LuWzRPK}=Ngs1RcqPqH)?flSq?|EFdiA-| zn;^QjS;*k>0~bEgf*Lo+87l1C4qno_v;!{Emb7^;4pJq4)Xe5wS1fgX%}?36Nb-+) zl=Y-ZA#z%!!DVlC$ErzvU|U)|m*K;I4iLqRweO~|!4P9d6k11dEGJgaW-9K!{WZ`2 zDF0AvP}e5jNqR%%1uc8I{&6OnuM>}t{*_n|7vceUIvQ32d;fijv~qO*1cjMs*~k1s z(Cd(-WOOGodNO_qk!0%LrwCG?CAXOFo-A5^D~#AKYXr6-sJdif0ySt)D#*gODhuJ7 zIt5F}u$|p>vWU=ZG6Nt}ZwI|$a5g%!J{#kl;;<&Xzqqi4n4$a%`c>^VKzB3uq+O7A z84CHqYeD^zzB{~-XZTgVg@2vY_!fnu+p167x7A;^1SswV4N-(p9Y8-Y6e3Uj7bGbfLEmojAK?oh z({C2*P+IpHF=2&zg5RB4Al1jFq+FSQ%^S?<4jYfC76zFcE|}`JxTMm0jtM47@2O`# zV`k1|2e{EuizhZeQrQDCBZoo=MUqLJTDIi|k>)N6|D44ESz=gkDQ!bZG zvMrFlS)oKA{&sZh#qj3bU-kU3?QK)E3*%S|yxKB4U9r`ly8h_icbcWT%`$mb0FxHg zLpB>(1B^3Gt+ChG((qrkFjNe#!&jUTB=u7C!VW}RqeXGCC)lL1HUWoC?icP^>Tw}o zO7)aYgqwg{0-bENj~O#lq?h%0E)I`4ui4A;@7tbX7|5i-sqQTu%nc&)w|Erk8Zy_q zFNQBQmYl;jj_(*JS_rCIea~^L)c(@Xmj%FDkERu7=nhy?zYL?3QdXst0;#4X3~Y64 zj6h)5Sd9@y7;#O)^r`E;8H(TM1dNXW0fvvb>eu7W9vY>9!N6^N-i^Q{~l|JLU`ycqft>WM0*cJ~a0 zB32$xbH*9q09=zkM#|GWd-SX*Zw0Z{r~T@aR&_n+paF#hn+LD+1EUSy{e^}2frzvo z|Mu;=h3`on%+@DAiy0eV|5DRPqs4Uz@0s6EL~oB}aX5t1!bp+7{Vo5j7|4Rc(w_H> zmuG#k@%>_hHX%Rm++5xq$fazIA3zKUxNT-nmKVoylU%HX=IgHKSZ@57aJf4w)Z+2! zk3zIL1k_n!GQz_lWh0n2(=ch{#zom^nwD1fe$gdtoalaiZHB6-lbk2`{ozO84;tyR z%5?UKmL0;wC+G$SM!Z&vdi!;G+G=VJc#v!;3n)1P0U&ysCztDMM>{iLIt+NbZfF~_vcX{f77 z4}{@<>)8Ic#nIQWk$t~6aw!x8MT@tI-KKwxQ19Cv;Xm(NkAxEsXQj}jgIrQR4_Lss zYIbtWzQA2}PqLve`(Lb%dL{{mCEp+TM%PwgH~{pOUj1Q)?IiY7UFN%Dh>*VZ07@EE zv=2Nt9r7HOR9*KyGkQV=Y@FH6>6+b4oS@pQt6SbYUGEu9=Z`FC_KM7E`*z89eeG!W zrQuhM`IZ)b`4ORr{lcd+{TAyB10h-rRn$oJo?8}6#-M1DZE+^YSo}iRcCmh<@VBdW$n>#M1hqIF(M}QB>s$_tvZH@za z*nDJ_b`p=a$v=%5-c6!x{HUyoeTpECxZP}(dOj9tN?LEU8H`vT`4RSMSDt;e$W@sW^>M% znYah;2al~(lX7JG2%j*t#X2A@vI;(}tvv`R()&oLR1xF3ubCq%@6?0k^}I8$$eUkt z`+*E>R-L}LG+CQU!t?pt?QZ>|UhmPXolWKd2w}(Z(ruZj^zT_T`VIfqbu+ez341$$ zg_8@#)B3Je!jGrha-6I)RpN$j*uWC&NxyF84LS=R@yrD5TnhJ~ZiHR}5P!XGz>`^5^OJmQzhEIjP+ zTN=Wds6=V{oT(owqub-L6`?ekIaz6@=x0fR3X}&Mw3-R9{aArkR%ac!2&>r=23Z;YAmIWnyRl9=!;lj=LP0KH&`Q$gMwSg8 zMY2#Fxlc9r2QH5ZBH78oFOL(i05eg&vYOy|=;q%Mo}T|jzTA9NFA4!tWtidD_$FscUS6R6 zF}1KAcSoi(uThOVWQ1|6RwZ4G+dAkc*Ops@Q*+Irw*&clQP|qgkw9Seq0H*hHdvhq zW$Y|xV#5-a)wMf^SH#z8e>&!=nnOKV%AP}=P`e{#;}9gBkSB0}YjYI< zz#ZCP)O;%YQ)Q~0o&q9fxQtBLefv3;rh@|zFFfFhsOZQTQk&)Q;GlpSUz;`VAZUzrl_&JP{dAAOS$3_Za60(0TV5gGYoeK`R=IxUX+f)X zM!U271JYO9By`@Vw7_s$-_uRtMH)7N6D)qFi}GD41}>i!VxIk%M|KATd_&M*C@>-^DHkP*aNeog0;e*>i7h_TJKxl5D*wvQN zhJ~-)D+if~EsuI`Atl4iwOi1l-9!rGQXBMVCLM?05njYjDb#@^Y^v;SYH`a2iO}Ns z7<9rHB@pIkRa{MZW5lot+ODOL+>8){9xg=kx?uGkazylf;`kgfG54buXI&qGsX}VV zol*sTm`#$Aj#OJ6IU+?~_To!F+kxRw`z+)Q?|93hQM;su4nK7*4V|BUi}X?`2&km) zojees(Dy{Qa&))dTXOgC4)CLb{mu^sSDH3zP+Z1Oih#Vr0q+75pS`SXl_3n&Z{u5F z(2${=hRNx!?sSabhMd%0L))Xjeg!}IJ$(ggeR;2&@>a;ktp3)G3D`lV++Xra^1^8* z{1ScRP-ogUK&vpyy3<`7Bfs20J_iZ25Tn^Tk5Mh*R1AQ|?~BT#VvTacnGAc|L9bqx zF`FyF5~F1aS5S-f#&OnFQCPFq8{+PlkWW8w*1-+$8K|KaG04)Yr4!!=XPKSOr#xFgB1t~rA#NKDID>O#Zj9g z*#WJ`9{*k1XExq+PaU#dnVKKuTaVs_EwEW*pTWAjtg%3tpiuVOG%$#^EBx1_oJ|@y zAmz@$mHRMedQqwg*UKq9hwHm;DCoCMrC02qQ_hc73e5}V1yG{fu6G?(dP&HJJtf)T z{E^0`Nc}v5?zCqwZKPE@b6$@q?m?XlOYnD#tLWp?7{bGrhMFv}Cy#MP+?7tibRZXv|ow$?A1 zG9o((uSf2h8=<2VH6BK8Za4XN^Ah6Q_o~y0`AVi6Ig3dN`6f{=|5lmE$f0Rq40^ON zFr1mkcV!$2ww?WT>FOH51>&EvK^~GV7O0Bz<4yiztn%DlGB@4iT?*#GsEpaz}~2?Du0 zvh5XC?rLFM?3^2^D`+TQ#Z-Pu-N^sMVmS6FyScf74EgK$C8GYIf3rO-Dtmv7zA&Tz zD_ps+OSkPzd^~KTM2^7M%@n^;DxUidLLnGp;r`6sEWc<<)d+tV}SBBnF3~~MZY~U99>0r3B zlVezwt66{5nAZ+>)2}T8_(Zk-#*Nz3NO@9oqfG3uH8byt!Z52(4$R4)>?C?c95ski-mtprc`X+WJc|pqzUwfacruC)- zd7P?{n+g5Q1l_2zUHiQvknKjtIe^LILhx=E=}H-S6<)9 z_Yh-OF_0)IQBBaRFGHrU>l0Cxfswx6IkDAz47N4lU=>oA)67%BTJ4@Ja41F1yCRpL zDoFWAkZs#@H#>Sj+hS|<~*8S^N!B|T4Sjb(^hmer~>iUkm zSyP;BCg+qfKsmlxSnu1hK-pkOf#pAHbU9L^pWTKTQCFnwi1Mi`B%I+NZjK28o4h%z zLn+}<^vxNNsS=UhSig#&k+^m8U}A@OwY&% zjT*l&I!K6hvh3cS(FnLH1Gj-4453{{C%1V*QzviZ71`KZp#WurVY>P8(9SeWE9Foz~6X8 zAi!?yB3QY!_7PZGR*L1w#gV#6dOL#DX`vk7UQ{)dacN8fy9RtuN=(htkqr5MyghA; zHcnv_WP|gXSl)Yq8|s4XDL1TUYq3HGyQEN~v)-sB*Uk{mNTZ~6m;xp|VUQ84}LmTC*2JpsnI zCntpx=?qssl@CzpwSw1B5JPflS(Emj*2C`!H($XoEGH9y$fXbBQTNLSJ57MFc1DGs zLW7YElw$50AW!1&e!pSbeDhcV%k5O=MQ`myUZEQ9PC~Rmz(rV=aMqBs^Y^lIl@Z3B zn(?Lzy8dLbQ#;gg^7ZR+t-*C_?iZ?=tnUKVhE_=SGP008#{zH+6|ACWqWlXX#K&|` z%oT839+sK@M#`YUbZbIjT$Q~eMbP-%__=9aaDJ33wj-HFN<#GH;?u8WG@r@2V}6iu zy>`c!8z$lz1K}tVC({v|x~4~|#+K!tm#32ZQpcM6<69zcPYiMBsN+oa0Woz*yA(dF zbw{(TGgRNRml=V(v8y}wbL%bc(kZ64C{JuxtKZohf_^i|cnZvcofV|S5u)=DT1JSwTRS$J06RJ?>2-0Pg`ezk+gno zu)}*Eqq;D0p_;vPVEsZmFw;t`7d8(i~I-x zp7J$C3nu7~DLn%vUNnOrvP8f{$$!4jhxSED$r3+^$|_aAaAbooLFxjakAX%*cA#dr z4Hws*BJ1MQhD6u>m4f5%$BHT=A`WxOOO9rK;7p%WE}x6O9+i=%uUX2&Aq;o^eb*1wR3!k9g7~l;c*pxJ za%oXIUtV`YWcco$zLKIz!;hBEP&*3``RE28K6F(k+v>bKQFcSNDRI(cE%rAP`i4~Q zr+_75I(DIqhM+f^Rdoz6kuziB>%y%i$SWCAty$~fLPHGEw~^6f`m=aJyGh!doUu_q zD*nf>IJP`&%rMRQ?#D!a&-u`GnUZeRF};N09G>$_rlS$gtsnc1>&(>X#G0acO`rBz z*c$JUY3Udse?>amIrigRugT3B7wG~ic&$iL5E=UsxQ3bPeLkI1_pu=U!>X$M z*pd~1+gc>y1&)-g4nc`Y16XYg)meK*b_^$=VmKsLz^tG$C#6O*_Kb*9P|dX{pcy=&^FcS$h07_?fQOsreu14p)}YxM;h$2WR6<+ zWsd3_@ZB;;^$a-veF<nyqbO{g6MU0g^h z{uqFY1dS*qa$nP~J@*C?r!=}Mo)uht^v0OI7BV#Cae3r{}^LE1VikOa!F=;DxedtU&ejuQ%*SU+A$Hiu{`hppOlgw22p(uonCU8VoFbrQk z|EV%mLLiKj8eti`T=k==)o_XH!@2E^#LHAn;Iu9Lbn70_jduSmu}uX_$`g1EWa%p9 zf>q2hSxl5nKCU4xy{EUUZ*0~quas*s=$+=7cIA5P@Cd5Awt*^0*6m-924vZ&kLmnC{;($H_7Tok(_* zUq-rz)4!Qb0R$=Qz}t(Q##-z-nzrKO5I0*UC32na6&U~1b~8DlDeuGcN%`9|59SMk z>+OBB!=tu?qg$QI+w0-VvFTJZzmq3E2VLvOo7R~njA(x8TQwp`&+k$tKI4)gv3wf) z2|gbHkQ&__pS7!<6iMEp-=f}sR=QlL@?y1pIzyw^$@Xf7go&<6^t>XmYjGSI6XM9PGz$X;7qO%0K7t41BdJ zqETbmhVuEuwDP4K+oWW7k3j){8>5@jKD+G-fXs~Dh5F;VjWtEw%%@{gwR^9Pbizjh z_j$>omRw`$1UV#&Md~EvVsW-veV=VoPYrV&=5FLg=e^iFQr%|wwL4Nz53Dg>?4(7& zuNXX4769oheA16soNUIcY`Bz>&S95V0K}Dr6irv_;S?Pz7+$S@S6mL*I9Yqm^b~{? z3GdbVv)S>R+-lNXoaCQjhKIhXxJ-;c6zj(-R-_g*2Klx}Au6=aP9CdQiJd{jg@45# zRb&g<&b_wodVks_3R_7-L0#%Tb2VT3X=K^natyl3K-DiO=HFwYHiK@jiRS;-WR8Gk zZuy%wX*e*0ZGV|cPE^<8<2Dj?G;(Iuug#iv^<{|vid~1q^gJ%i&s_X5N2kL+wsf}W zy*0d1pmUStaJ8!Jde3j@WWY^ECZ^(g+7CN^duitSgg;7iJv^>>9w3U1B_;Ua*UUE2 z+}Zc@F}lDh5b|oYZ zN;BciVb*5xXSr)tK@3w`EI@=bEq`BTap%ddp)f}tZ0?WN(+xjd=_^1heTM#2>0sYk@x#ukTlKUm6l813ZTjQy>YSmDdk zGqOLn3aHyQS4sr1m|pzlk04BHl+r1-jR>*gI(S&I#?-4b1{+^ht@G`^AHimFj&d&%9un&)yqt zdv5XFb)M^4)p)=`@IHV$q8#`GW1wou7x8UI?9U?>2Wx!1;KKO#Zv%sih#GM~0yG-? z4^kkWIE9z0i&C>iq(+SfYp}$!kowq<7DNh;3M#)}?F$v*ETo$Pp)7ZEhS&m}_SrBdTLd`XeV8`L5hF&#@_bmkMybjTQHf64uWpvrET zLaeTtOF}Qr3;G1;8TWfLqkprwf>;i?lUSg2rZCpfV_}1F5fI*P34|P*D3)K8XNd&p z6{k1ORli|<&6koDBvCk+n`(&WTV==*V+SL{^F)=0l+d4*9WpY46rOLmsh%n2Z_aJt z2n!Z5QyyNee5+7_`Zo_>^k*f?Iix;j^T|EZKI@FP{5}Bsd*yTdl7*$CF?>$DuT`|5 zRi!P4Z}a3~#T37kDQ33oIQ6tThu;#}jP^z#Nf;H{_!ealZ=ID84tTIJ5F#Uf5aBC%zB~>9r+BV1-7D^pm?OGWOEx!53wGq!QZC!2O?g z-_hO&>_s>Mw+nCIxpeRFLf3gD5YveI<@DyA4T;E^yp`8M-{o1ui`wco;+)Q(wjiZtGM!$aDv#f?tzpcq)gsdr^DNZP-C%M$x4Oj z$>b+WE;g-#q>$AR1mLc)=42Ad2`%L7OWG8~giH%SUR0&F{b%=JwIzH^)j^t1COCm> zAWHeVfjOBe{T%cY+%NP(|GeHa&9Apg-uI7Io_X|wpxA^O9SsW%^Gdlg1!#r&uH0cA zB)q($M(4n0T}}0iL2fRR056&;Kd|(hJnNt)g<+TqN|RQ~1{w+pTE?nm?iRD*?c3sU>8jxToV->t30-}GN755x5{lZ>SO+JT0;>I zc~t!nGDk1?!hb?Ho6M$$4U7cKKaeM%sliDTEU4TbM#@o6M_Z=IPgrf}1g+q-YZb`w zu>)y631hyyua(zA2<*fQL&8aB{vg^f2BMePkU1{LV!LxdR?I1 zqR0F;C~IA1MJIYeRv5_X&n9K~$!atE`!Q0p<6{YpYA$P-Kr9qlH6~uiZN{n^O{#jL zd5~+Drr~bZNALVx|C@O~xQ&U_7awC}bwiUY&rQw=P;a8y{1kcj_Lsc7_y$wfa~Z{R zt%ryAgk>fkU)`&iPxKq0_BbTFj1)PPvtA)^bn>!|I5#sAaj+dE{Q@3|p6b=KYE{Z* zjff{qF_xC26F`jQeTutHQDK31s?n(<)be8zy7lSI5k>hReNvyVRKc_DczE23N@!#9 z7~l)#92gQ?oqoWz8>bm#u7SA46|)zd%xi|G;fXSpnpbAAD1b@1e<77xW+eqY_LBu6 zYnVgL0d<i<&krYRc~Cu=mhTr7I3tF=n? z(^^KWbo_0#a?y&{*i<$-|5HU4`V`tdot!6jXqa4LgygurL||room& zmRKg8=KEY#vA3i|&iCG*AB4Q_Bh&JY_IrrmoA^|&ocf}N*JLG#K7ZEudJ5YcW!9kn z>p{CBt5S6LkN0jY6uF#DT2+lD*+7xK=zeIg6V!Rs5HYplmv`8vgTT)R#Xr!dQ$xJY zH?QqdqqFIy#rw>`3VHIcE7KhdEXw=0^P=fjDQeYviW0bNu9Ct3I6<8pYA-v~f`-*L zxP}eDZ6l~n$zcOkg&2%D#{jb>a}r&ZsW|$LMwX;?35S!Yg|8dL-O^BEFO7*JDeK&} zk~skm$iG9q(Ge86ukwbZ{ z4Mc*DgI=^inykY_1s59f^i@yn4!Sv8ASY(ONaK}NlNOSp9eO|Vk?3Oq?L(GmRhhY5 z-)CWCQLOVuY#X=dMHw77G4nsP--h|U7d=`A4=R+P-=#3Eo$%@+JgcE__S>(uk4?Bt z*20f@Lq?{wU1&w`K0rLniy`N$dP%AT-b9IxtxpOV8)vfh?9x!Xwm5%|Hm z$`FCS>Q{kzslq~=Ac*i53P~ZaXSsu?`{>khn3h6|%9%p=1(P98i=KBakh8Y*7w9!5 zloUreP=#Q&sU{O>K_G8q_i$o#>RoXE8;qJGL>KcTC-EHL{}qUeTMpy=q*mJ>MtH@k zf_>KeijhMdBVOonjV_R9*4Uk_pG@z*MJiV#k3sq?H@=*S{^xtxS6#$qY)2w}=t zBb%Er63jEMiz>Df<5SHQ#hZSWu~BDy&|vr4CIC_(!Y)Ry`SMmyDI|%6quP6XHDYXU zS9_^zuAjbMDM|L`3ndBt&s$@RTmY{brehqn8pgD1T262Hy@FKQdFBFX zm%l!AiIIK9?|Mha7BK%VKW2f~L#YD?pU)%mV+3C4_2QR;qGp}&@E(R;r@H#H!GpXN z29+QR3WIxK)iB7~GIqc(NT;XJDK$gG5wa2c?EV&5C^oT0wEU%9hL&;|m9SBFwYit( zjL#AR@<5De=IX=|Q?lzmYQ(4K}oK5Us^2-zZG; zmBX+!v+3W5NtXj`+wx7{@KvWap_M~h5dNwufqd50&l%mE76iZYPi>=OTs#VuO~e%} z%?cmkX&NW1azf=C%4yypo4UN|GonV5oK-Am6q-pBM8+LlbdoZ(hfi!>q%_o0OAUZ?URKU~{Q%knwv&Of8>BgK)No_rkj=|WDAPx{Z4<^1*jU?NWO3WL3T zJ@U_j$NdE-`+kmlI28AKD<4BNBW`mMM#an4nwj1A)3SNcX#YvWpPITT*lxPgmzX^K}p3U;(klL3Zwcr%Ofsk5YPPf6IIV3Zk86@(7UOIZVjV9D`k?|g`o z3ixV~>L{v8fcJ6bxxf3-peU99^I#>&x2)^Nc)zaWtiE)7J)Px`3FJULJWf$^AU;S< zkOnMvjeyP75IF%3pF5@)-ZrO zxySLZKyeQ)U|)*bXwJhel!r5<#?Sc0x?Z%41J<6#aB_*IG)_|-)~k#y@=aJ#0iF0} z+f|4lRJ4~n2@g1k@NoTN$Sx=@y-hB@=t)%;!_96-aUN-ZAWsE%wq>iA+8?5>6m(Xf z@)@ow)O{-c|DuF+B zrk$URIKaV_5aL~ZeZ7Hh@D#%NQ*W$I*8ghpjYr!eR+ib@gr!}z^iX$OJLl9PgQ-i2KWP}MnaWpd!9gnZJdT1~&p|NPpp zu5&Qy?FjP?n|h+w$jWo!|B@;bxBeDv@Sa_cM7$c-IbB100pS#qT3B))aKTXRQ}};v z)0Co)Z;2tt&GKfmeL%qEIqPbABEabg_CJ0We28jdq`L>YhxhR?&I%M~HT!!CYdp-+ zcjCkDbi}GW!aCjhred*P@<`d)Co^5`i0wa9l+@sfcdYTEHS>`bioZ1L{z8J*2xvcqBP7BBnUq?P$rM>kK8)Iw4@a3QF)SHrC}R@KwB=~~iAa4^XggzeWm zJsSdMvL+pFxL$f1hNOz7W=-$0@ljKw$>c|@Wa<7pVWv!cz$9XNEsTBka>ptaMk%Th zd;kAqiM7vQC5BXBs|RVob!XFkA^=o_XAKc#tgW-J497zj(Ha?HeI*6({!54+eNf!` zbU}($>i@c~hvxrn7>yU6r@^f)*%PH)_s?lCj@e7K>W8RR(;lsrWd&QozU>&PG(plTtXh%RyJVW4@54)b^M4e*GX72nK zGfED4kMq5jkr#(&hZN|o#}vR?xo@*C+BmZvy_f0RIUZYM{3j9&Hwe#-8i^rpYKkDs zNx=oEWZ4+Gb=Zwh^+fATACbS?T?qgKFkgjsMNyLIET`{#PF7AyjA$>GMvp+ncktfHqU_^Q)s_%SmO0zdbTH z6jvupgZgGZPyU03K@0UdMs$&10wtRIdh+w@fAAci`3fXQp7$!QoB*(8_5yS%)CL!O zmoD2h894sm@|^GCzVBp>%L=ij-4|qJS5L&{Mr)SdJ*fXc)~Ekg@G0vBp+zis#O{oe zhKi#Gf48z^1UA_JALjA@KbVKB(at_u{|V%XxXmC{px!ua&bn~UwY0p2&~ z>-X?N)As#tFH58h>K#l9o%VXVo%XRjn9l@MjGQMQl>S;~+SLYRt#7E56mS(6AUSrQ^jy!SI>t8d@$`ThRy z`+wha-t%_OoM~pB=eh6uT0WoazOL(eoCrHf`l5M=Z{KPngZ? z!&o?r(BbTmBc2l#-*Wv%JMwMEzK%q)kYN~-)ohQK+6l3iQdmftn)QYxxVJ!A%2b$(u?# zFoW7sL2Qr~%wU8GOhS{C)rM)Qjf0Gtv@|xhv zMod$bJ9}|1&c58IWo~jX#423ccQ9HWJ50)WDp{TMg3BxL$1IbBVCDPiX4Py?$AFz@ zhk~boNuoSf{BR<^5ZnMf9(i)mm*!}L13abhQ}_Km8vz|Y@6)%u=K6JVo8zd2SYVjg zfd(e|5lIQ&8RAU|zLF}{ucYTr-*gMEH0OfhzZiI3vaVHdEP?_{2pIL#b_iqliq^xD zF(u9uKM-i6>1sA3*ys`L#^Hvm_#`+6k+sijN?fc&|BK4U&`n=dqq?iS>1Htr26Xm* zpKd*sC!+l3J=qE0G$<5yxhm5k{z3MzqATr*x8F9xP?(o4;byS$aG|Dt?`=H$ou_x1 z;rcrnpCYo;DKD4y_wp`_q5GSLex6F*bc*`ZrW?Z20kmp=~Qf|Y!_iTg09+ii0 z!cO%4s0Yjd+=;IH$3o_}EjMHo&$)Efy8~x}{EiAUEk}OKOHm^|+iA%9QF8adfdQNS zjhmJrlmuQV=4g_hBkgv3%=mZ+UPR&_PO2@B3X6!p2+Nn|>^>gMu92oo4d%hF(VjP?++J1ywh0mTXgeV6B!bxR5r+dNR0#2f&}=otgsrNMo0A-`Gf zI*-5TlqTF{b-cO=qTT8W@}m7np-r!~G+Y?U+XtIEk=TD)dg3^U5U%hO3SFyv-l7Be zpI?6dVeGaQDJ1dEs<42}@{eu8Fw`mNu5-(JK#;%9l4P`odQoN!3EDHwNE`Q?3c z+lTB24njeUIOfOPbXCg*k-}GVS}8>g-&$_S1FRO=zIEWM+}i8zuf{WA2Vp(L47)u( z1zptNGFutJPY|YFks%~X3pTioLapvVK#ex9o?XM)q{(}+_`qk+F>h-rmSok_c;jC2S|w%R&1ivQP1++HArz=){yEv-eOJB(0*CGfp8`w#DE>+ z1i3`^!r|}ro!IY@omg(U1b}Wlzsp0L1gW_CDYPD7f}K^ZjTW?9>xS*COAMew*{k0_)=uByx$vE{ zPi9dN;LD@^;z@KcgS3XZq*8J$mUtpCEb-)_vzdD;XL>(IAkeA$L&?{aypO@ze1pK= zI?p!<5XaYYq08nkym+jJR29c$W~`Zbb~l#pk!mO``@r3Mr)i)$s_$J-Cba)N> zp6|kW@5b9n@1@pZhSy`+R5?gQ%@652m1O~u( zV(L|B4D9sM^vaSHww7O0NEX2cXSdsxejhsHoB0GcyU1xFg>8|(_K6`i;mRK`u%8p{ z1E}6Z+Cv6B7Nqzp{^!hSRV()mJi^3jaRJlLkaDmR`v9=kM-YfgBC)SGtq@)7d3@Q; zVrug6Jx~k|24BM8mtN8;(&j%?nYtCzKwTm`72%Fc1S7*uOVvoRSpd3X)Zr-{a^nX_ zefZ4{IamoZg}ml$9phUtKNu>0JarVr#+<_o?wbJ&rfY-5e!g>@9Gg}aMLd1K2B5)t*89g}MWvV~9P+mDy7%!b$4BX{pZWuV?iuv(I72A5_+ZI`qxdt6a zbrSDJjAZXBJ)B+{f)bH5vJ!${9hE}AV5C)5XNDGB!?Oy4n_)!01Qh6r9Iz9oeeIq|oII9u-#kP(_!a+abv0=Hiju$roE54PSYA`swp{*M-c$zqtS<9-xqg zDei#|j2Ktar;3iKmDUDIITg17XWqABPRkZ-`wHU8qwmKS{Nm4kh#1Cr!2y}%x+Ags zUTp$4A?QaYps1__R?yCR!2^MIIT&7Y_OBu%@0)Z%+@5MfYSjPOaeV`Hsr<965gys_ z5jasuU3A>a*8535(+pfxyF7iGLfEilnHB%As8?~jbrpf52;|Xyr1tcgr5bb{1OD&_ zJCh>s^`IxwQR0U;&!vwmDvt)iQ}j;7ohx6MPG8FEbPTRI_;{wn_AA&#E6<&ViC-Vt zfh``dn*WemR25x6;0U@IzkJ%~3ps@#1kj0Sk75G8VzMX&`6BAsHEIOf3Ygz5jj+ul z)AV$UIx$D|yg3NE@uHJ1wM$YGm%8t}(Wb{-1x9_w{J~mEfR*s}JU+R%L~bGkUk1}i z`}`_Xi($ssjp0H-N2$jk&Zt?HLd%!}Mqz7kCKlN7BFl{TqTFP!I=5B~k)nxP>bq>t%L!VE%&p0#= z0=;bNqzG2_DZJZV5b~cg1{jmLCK9Ve_Q_=tz@copcGFcnF$`Y@4TwNzA+@X?nNNhmdV{zNc#xOa<(4#mO|JrkQ z)W3Er)kn;Mbh5NRv@KGm$8R+MX>L6~*(COP0EpiVPe}zTx^fx+*0TY%z+V!O!sGsU zXNMyUg)L9;0_kg3f_-6dmMF*r>Lu>TXt}AAZCTxxW9IrilnJ_2AB;&OO=;_ZCOr$I z$H>9(Rf{qLE^;;8lHKI5Hk%w z7;Z+Zkw%d&WsN{riE@Xk?Z~F`c@sv1o&}x)%nnj7nNOh1*nzwFv|^OJ=E;z^Y$P|umhB~z`mDn>%eJFXxqs` zZ=LjQ3w-{rjzA!K?&|_T@ayUf-GX7mk0j^4H^w%b^q3*{4-Z_D-rR9~2r@?;14z4r z6>b9N0N{cpQh?7xb4;m#v9h^pJd*bk4AUx3!1GBdf7hEk!}-w3hd9Bt*!W_bIkyhK zZ|JcqNU+LCEPM6cr~qK>)G(AS8B>7KfndUm28QCT2tc4OuJ;%yt~f^qG)AyL^P5Lv z>DPjx&#@Ds@h}PCnkbOl>jBq*%zXU_OybI9qyGK+)$*9+TIwG+&BpuB4>~2*0&oP%s$Dbosk=K>agvwm` z_^{Vc(%!S{&@H!{tTH&!X#3kk9@asf_Gc!wy?sval%PXlEBwDTLHh(KfqDw#|LIne ztQ2#-mn3I~LWbIsAZuk^)d?Z2M}v@uMeieTH>I(A6E!I9TL)pNRe}#LMNFq(vG^~RuPZ%$p8tq zGV`n+L%8|4P_Uzky}`@_HZ-rDlT3&j%+ZA`bz3oRt+x$ohs5&&o}Am5;~-IPC$qD# z@X?3_*w92uX^Uh~=exGv=1Qt_o;Q$xYkmsj)^+a?bi7@tg4UPJA=dJ{kCHAK^E%>} z5OjS*eGga&r9)SaND6>@pZDjUGV`+Nmm$n5`@;CYzb&n~vn2}eY{Q>41Y9gzXtSbl z5JuuW2m!(bf>M5291SK))BR!L_AT~?#gRtv_|vSM2Zv^@Co<}i%7>!|a4;4~m`+V>iK1yC3cPmu$usNtay zym({%3vdPQPzCP*Hb4X;fE%|CK(Pn;IBpnGgaTF|6${*sJYSF!aZrJ$0F(Uh@^PZY z5!=L>1KR=S88`;cSbX`E0QMSxn9o2e{!qACojj(&CA@?Zs_ACCCv>GLk~eibxEg9)BTZ6eFd6YckrMmk!f_ zSf?5!Rtg9WY&rQ5ghq0V1c4O{29nXNX~OTMmbFABMpp{CK3SdX&LL|Hh+LG6Q4-+* zApaJ?HUfk$0~8K82;izLEksjZw7^jjXb|#(RRS2Hg`vFGA@4t(0L92a>kxu%1~aA1 z0HEpmbD)S}IlS74$wNXGMS;}yrbEGJ%96i;-mDIS=7xZKNsl-ZT_t(j4;;0Q4ghqtPF{im3CRN^@ zpNUsN=Dw`;n^*?L<7fg7Yq;Jy$?`wR=7?&=R~nN(G&v|IQxC-ADMPj$DC&6c-| zyiUOZw}7x#DGx*1vI-I)Z2@t7&hCEyMgfK=86cpbqkst&&JqK`1v#87rpDbi!(x;* zvp#W)7Mwprbp3||SM3vQ`=7Nm&|=K4fh0=+8vz24umJfqVdKda#V*Th{gevGiY0=q z>SuDG06B1|!rK}$!$aGLb>JufGdT1&IQ#z#xBiGkV9M06f7a3p$o>k(tJ3|m&{k4g zzXv71K-FJ4V_7UK>_CY;{$YeNknROyg*arD2%xZXeINz=@ZSjN{?;?rYZ@}Xl_8hK zBDo1uPxMpAH z7`R)~Wcp%yB5=ZgWUs3DhB~<^>#5{Af#871^o93g^yNFu=9z=OPnRTN|V)WPMsyum!`GrzfXCe6L# zs)f`Wou{J)9WFh7KGDYoM&t%NJe-X)y9-Najt^$qbvw;J7TD=A`g)h&URmf(M`mO? z#s!3GZeJ^v-+WIBESO||diV03ye<_Xb3GtPeyHI8g!XtkOYSW^2!*6C%ufkvN5P9c z25U9%o$6Pwh?0G8`fx*yjq@2J*60~}_cWyK zp?lvu_5nSWr3Ej)$r{cOt3^tQ3Y6FY1y`BO(11n^7{)V-T#}o#A;G4#N&>Cr_U1t4 z6{r>s!yts~DCNBgY7}Q<{k~&J>>^Z?&L0LF$K`Zj)4gB}iGJ(yB_$uNraqr7Qez|! zuAZ@)*k$;^3ClmXJP09kHQ|gJb3_m}fndVjyaGe681ho;cc6{}hY|bkfU3A49EVh_ zC70UPtwZt=ly;!J*$dG|`8Y z#pdi`dmhHjygbU%;-_F*J+rw9H&ecPiwgDwq+%3vJ%d?qRdDbK=xNUJhCkebhG}0YfoShnK&=3{@ z018APQ*C{Er4Bk77%n%$U#pv0!0Me+J&S+&tS-StsMUWRE3NZa(JNr(Psd$b=4C64 z>Mv&ffmK)~u_j}#$sg`FoM`;IdcYcXD_jCpVj+Po*!d@@fc?r=e}{~JM~CaC`u_~z zZzhsy>7O*~4KML6E#aU5;ICY_^NnSOLcfj}EIrEHd9^*}&=L;ME(2hCx<5?d)o5Xr z!$}S)yL}aYGm+Oh>OkWtM}Vv;)MY_wCA;{O0cZJy+_eHaJ2zoU&f&E{4HY841Q_n< zM$DxR7(IQT@oufby35R<*9%l^f@mnO<)H`zAmzH&VYCt&tSf$k?D@(#>uQ{UyH~;m z@^~IA<3W@YD*?jeO*oE?xWsE~0RR*TtONm;k5?A~)?(9Dg~U>Wex0>i8)&Lp2@Gr| zfss&phoH9=8G#@OCLW_k+JVG^qA6H2+*IT|-dc^c4Fn);Ykf*k&r;~JpnhL~)qMm3 zuo}sujxWiEODyfwruKYW`2$)n>3*F{yB4WhwOS)8ez^hCIG_5&Ky^f0kyBk;{cvxE zGBH_B?106;a2gS0OaYFNr8E#uj_@eV{OfWez>aVwH2BGA$O>PMR@gyVbFGz%V^$h& zvyp0jSsQdctvJA+WegcOCQ=B2W`Ntk$dL)oTo;MuKoH;vLiIWWfehvUjAYfy{~gIg z0T!|b6c0efU=z8s36m?VC5Zi?*L@^a8W0Wpy2b^lfq`pQ+8u@}*b`~ZrOWiI=|OJb zi^3+^`&a{NIo5GEr*x`bl6~Uwv>`lRJt-SD-r2}R{q7E{(x;DN)MV_(d7`j@6r?Sr ziW-b>+?_H=-EFe8_){<8%{9E87~PPv&)7b?6niP?lkU(qto@_Y;?S{iHd2*`7BplG zS-lhPG@O;j?oO_k+j;8U6NKnRsimm~X|smYb1Y%m3L~jH;$y}7Lt%U#TlqZRvnUd! z)2BhJl0PZ4!3pPiy?zIvE;8Lj*oRIXN%%I>eo5){uyO7(%}ums8?C1~w>J+?EYn;` zurvc`(kXTrtU^x2y*}vQQi^Ouf`;i(siL=hcuOlEgxYFKB1~-6ek68$IGQYQb z0srNgEj%VpxqVC*2^t}nZ)&0z1^O2d>iL7S=U8QL0QTTaUc&1?Xu5ZfbNC>|MqSDul*vg_65;-upU#4 zshFo5AsQLGBXiV9xq`3WX-1?n3o}sK$6+%c$tet~18&K{#^fc~y10y?22e+-BFN=u1!=I^`VID}I;q%8w7V z$o8GXTd>KV$U?qe{W18Zxx2?u`>h*-*!FNc`TCLKNlVVvE2dYsYuWKxWP?4gg`DSG zg}eqDJA1X2sV}nRmy{}@om)Kp{p@^ALGz@>STw2k;9xz`t$dFS4ZVil&#jq5AMV@p zqo^(l76dW2cusdqT~0jz3}K}jiY@a!k)+e0HsmxSRNydHTzvb-CRjc<+gs##XNzlc zy;^@nN61elC6pQ0_B}0r_Z)Syoh7I)irFyFjt&#_o$;rt^MB~iTs`rK8HjLa^6u{A zLq1%0xQpA3ZhMw9nlrr~5i={Zr^yXHJ`RrKI-Av8XYX`;=I zDg7RvnB3Viuh!0DCD0-}t)wJyM`>V0$mXbn&POT>9qXBX|3C~Wazn|LZq011^pM=T zwlIU!HeVI*_~{3B{q~hjar?#O#1l8N08wqro5b;mB5K>%M;fKazN=SQpgczV z3Ixglm8-oq6?4qv48D6>lV95zoLdkUUeT$i<0_v3siDPaNH;yM^k_C zbu6(qjljfnA)>>I0Mz$V(Do<3H%{-iUxQ^je(L3eMIu4Cof*dTUaLntjS$U!p=eah z#;TG8HVvXuSTh$CAc0Zy%SC?1q%}qSa`4? zY*vw>g7F3CdY-4L6VSJRT}`BoqaLX@8tY3o=y|;12y_-TH{X(4;5==ROVHsFrWslZ zz^d<=xcN5F)B1efumvEOvDCd12%RLDm+u04b`IQf1pWy#{E~j +#include "jkqtplotter.h" + +#define Ndata 5 +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + // 1. create a plotter window and get a pointer to the internal datastore (for convenience) + JKQtPlotter plot; + plot.get_plotter()->set_useAntiAliasingForGraphs(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForSystem(true); // nicer (but slower) plotting + plot.get_plotter()->set_useAntiAliasingForText(true); // nicer (but slower) text rendering + JKQTPdatastore* ds=plot.getDatastore(); + + // 2. now we create data for three simple barchart + QString L[Ndata]={ "cat. A", "cat. B", "cat. C", "cat. D", "other"}; + double X[Ndata]={ 1, 2, 3, 4, 5}; + double Y1[Ndata]={ 5, 4, 3, 4, 5}; + double Y2[Ndata]={ -5, -3, 1, 3, 6}; + double Y3[Ndata]={ 6, 2, 5, 3, 6}; + + // 3. make data available to JKQtPlotter by adding it to the internal datastore. + // Note: In this step the data is copied (of not specified otherwise) + // the variables columnX and columnY... will contain the internal column ID of the + // newly created columns with names "x" and "y..." and the (copied) data from X + // and Y... + size_t columnX=ds->addCopiedColumn(X, Ndata, "x"); + size_t columnY1=ds->addCopiedColumn(Y1, Ndata, "y1"); + size_t columnY2=ds->addCopiedColumn(Y2, Ndata, "y2"); + size_t columnY3=ds->addCopiedColumn(Y3, Ndata, "y3"); + + // 4. create graphs in the plot, which plots the dataset X/Y1, X/Y2 and X/Y3: + JKQTPbarHorizontalGraph* graph1=new JKQTPbarHorizontalGraph(&plot); + graph1->set_xColumn(columnX); + graph1->set_yColumn(columnY1); + graph1->set_title(QObject::tr("dataset 1")); + JKQTPbarHorizontalGraph* graph2=new JKQTPbarHorizontalGraph(&plot); + graph2->set_xColumn(columnX); + graph2->set_yColumn(columnY2); + graph2->set_title(QObject::tr("dataset 2")); + JKQTPbarHorizontalGraph* graph3=new JKQTPbarHorizontalGraph(&plot); + graph3->set_xColumn(columnX); + graph3->set_yColumn(columnY3); + graph3->set_title(QObject::tr("dataset 3")); + + + // 5. add the graphs to the plot, so it is actually displayed + plot.addGraph(graph1); + plot.addGraph(graph2); + plot.addGraph(graph3); + + // 6. now we set the graphs, so they are plotted side-by-side + // This function searches all JKQTPbarHorizontalGraph in the current + // plot and sets their shift/scale so they form a nice plot with + // side-by-side groups + graph1->autoscaleBarWidthAndShift(0.75, 1); + + // 7. data is grouped into 5 numbere groups (1..5), but we also have string + // labels for these groups (stored in L). In order to display these labels, + // we have to tell the x-Axis to use these special labels: + plot.getXAxis()->addAxisTickLabels(X, L, Ndata); + // also we can rotate the labels a bit (by 45 degree), so they fit better + plot.getXAxis()->set_tickLabelAngle(45); + plot.getXAxis()->set_tickLabelFontSize(12); + + // 8. finally we move the plot key/legend to the outside, top-right + // and lay it out as a single row + // NOTE: plot is a descendent of QWidget, which uses an internal object of + // type JKQTBasePlotter, which does the actual plotting. + // So many properties of the plot are only available in this internal + // object, which you can access by plot.get_plotter(). + plot.get_plotter()->set_keyPosition(JKQTPkeyOutsideTopRight); + plot.get_plotter()->set_keyLayout(JKQTPkeyLayoutOneRow); + + // 9 autoscale the plot so the graph is contained + plot.zoomToFit(); + + // show plotter and make it a decent size + plot.show(); + plot.resize(600,400); + + return app.exec(); +} diff --git a/test/jkqtplotter_simpletest_barchart/jkqtplotter_simpletest_barchart.pro b/test/jkqtplotter_simpletest_barchart/jkqtplotter_simpletest_barchart.pro new file mode 100644 index 0000000000..cee6fcc1a6 --- /dev/null +++ b/test/jkqtplotter_simpletest_barchart/jkqtplotter_simpletest_barchart.pro @@ -0,0 +1,16 @@ +# source code for this simple demo +SOURCES = jkqtplotter_simpletest_barchart.cpp + +# configure Qt +CONFIG += qt +QT += core gui svg +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport + +# output executable name +TARGET = jkqtplotter_simpletest_barchart + +# include JKQtPlotter source code +include(../../jkqtplotter.pri) +# here you can activate some debug options +#DEFINES += SHOW_JKQTPLOTTER_DEBUG +#DEFINES += JKQTBP_AUTOTIMER