| [959] | 1 | <?php | 
|---|
|  | 2 |  | 
|---|
|  | 3 | include ("jpgraph-2.1.1/src/jpgraph.php"); | 
|---|
|  | 4 | include ("jpgraph-2.1.1/src/jpgraph_line.php"); | 
|---|
|  | 5 | include ("jpgraph-2.1.1/src/jpgraph_regstat.php"); | 
|---|
|  | 6 |  | 
|---|
|  | 7 | /** | 
|---|
|  | 8 | * GrowthChart class | 
|---|
|  | 9 | * | 
|---|
|  | 10 | * @author Jonathan Abbett <jonathan.abbett@childrens.harvard.edu> | 
|---|
|  | 11 | * @version 1.1 | 
|---|
|  | 12 | * @copyright Jonathan Abbett and Children's Hospital Informatics Program, 2007 | 
|---|
|  | 13 | * | 
|---|
|  | 14 | */ | 
|---|
|  | 15 | class GrowthChart | 
|---|
|  | 16 | { | 
|---|
|  | 17 | /** | 
|---|
|  | 18 | * Male sex | 
|---|
|  | 19 | * | 
|---|
|  | 20 | */ | 
|---|
|  | 21 | const SEX_MALE                  = 1; | 
|---|
|  | 22 | /** | 
|---|
|  | 23 | * Female sex | 
|---|
|  | 24 | * | 
|---|
|  | 25 | */ | 
|---|
|  | 26 | const SEX_FEMALE                = 2; | 
|---|
|  | 27 |  | 
|---|
|  | 28 | private $style; | 
|---|
|  | 29 | private $title; | 
|---|
|  | 30 | private $sex; | 
|---|
|  | 31 | private $maxAgeMonths; | 
|---|
|  | 32 | private $patientXarray; | 
|---|
|  | 33 | private $patientYarray; | 
|---|
|  | 34 | private $width; | 
|---|
|  | 35 | private $height; | 
|---|
|  | 36 | /** | 
|---|
|  | 37 | * Constructor, used to initialize necessary variables. | 
|---|
|  | 38 | * | 
|---|
|  | 39 | * @param string $style Chart style, from available dataset filenames, i.e. bmi-age, weight-length | 
|---|
|  | 40 | * @param string $title Title for the graph, provided by M program | 
|---|
|  | 41 | * @param integer $sex Patient sex, from available SEX constants | 
|---|
|  | 42 | * @param decimal $maxAgeMonths The greatest patient age used in the chart, used to decide whether chart is infant (0-36 mo.) or regular (2-20 yrs.) | 
|---|
|  | 43 | * @param integer $width Width of chart in pixels | 
|---|
|  | 44 | * @param integer $height Height of chart in pixels | 
|---|
|  | 45 | * @param array $patientXarray Array of decimals for patient X data (i.e. age in months) | 
|---|
|  | 46 | * @param array $patientYarray Array of decimals for patient Y data (i.e. length, height, BMI, etc.) | 
|---|
|  | 47 | * @return GrowthChart | 
|---|
|  | 48 | */ | 
|---|
|  | 49 | public function GrowthChart($style, $title = null, $sex, $maxAgeMonths, $width = 800, $height = 800, $patientXarray = null, $patientYarray = null) | 
|---|
|  | 50 | { | 
|---|
|  | 51 | $this->style = $style; | 
|---|
|  | 52 | $this->title = $title; | 
|---|
|  | 53 | $this->sex = $sex; | 
|---|
|  | 54 | $this->maxAgeMonths = $maxAgeMonths; | 
|---|
|  | 55 | $this->width = $width; | 
|---|
|  | 56 | $this->height = $height; | 
|---|
|  | 57 | $this->patientXarray = $patientXarray; | 
|---|
|  | 58 | $this->patientYarray = $patientYarray; | 
|---|
|  | 59 | } | 
|---|
|  | 60 |  | 
|---|
|  | 61 | private static function generateSourceXData($min, $max) { | 
|---|
|  | 62 |  | 
|---|
|  | 63 | $data = array(); | 
|---|
|  | 64 |  | 
|---|
|  | 65 | $data[] = $min; | 
|---|
|  | 66 |  | 
|---|
|  | 67 | for ($i = $min + 0.5; $i < $max; $i++) { | 
|---|
|  | 68 | $data[] = $i; | 
|---|
|  | 69 | } | 
|---|
|  | 70 |  | 
|---|
|  | 71 | $data[] = $max; | 
|---|
|  | 72 |  | 
|---|
|  | 73 | return $data; | 
|---|
|  | 74 |  | 
|---|
|  | 75 | } | 
|---|
|  | 76 |  | 
|---|
|  | 77 | /** | 
|---|
|  | 78 | * Renders the chart, outputting a PNG image. | 
|---|
|  | 79 | * | 
|---|
|  | 80 | */ | 
|---|
|  | 81 | public function render() | 
|---|
|  | 82 | { | 
|---|
|  | 83 |  | 
|---|
|  | 84 | // Create and set-up the graph | 
|---|
|  | 85 | $g  = new Graph($this->width, $this->height, "auto"); | 
|---|
|  | 86 | $g->SetColor('white'); | 
|---|
|  | 87 | $g->SetFrame(false); | 
|---|
|  | 88 | $g->SetMargin(25,20,20,25); | 
|---|
|  | 89 | $g->SetMarginColor('white'); | 
|---|
|  | 90 | // Load data from XML | 
|---|
|  | 91 |  | 
|---|
|  | 92 | if ($this->sex == GrowthChart::SEX_MALE) { | 
|---|
|  | 93 | $this->style .= '-male'; | 
|---|
|  | 94 | } else { | 
|---|
|  | 95 | $this->style .= '-female'; | 
|---|
|  | 96 | } | 
|---|
|  | 97 |  | 
|---|
|  | 98 | if ($this->maxAgeMonths <= 36) { | 
|---|
|  | 99 | $this->style .= '-infant'; | 
|---|
|  | 100 | } | 
|---|
|  | 101 |  | 
|---|
|  | 102 | $xml = simplexml_load_file("data/$this->style.xml"); | 
|---|
|  | 103 |  | 
|---|
|  | 104 | $xdata = GrowthChart::generateSourceXData((float)$xml->sourceXStart, (float)$xml->sourceXEnd); | 
|---|
|  | 105 |  | 
|---|
|  | 106 | $g->SetScale("linlin", (float)$xml->yMin, (float)$xml->yMax, (float)$xml->xMin, (float)$xml->xMax); | 
|---|
|  | 107 | if ((float)$xml->ticksMajor != 0) { | 
|---|
|  | 108 | $g->yscale->ticks->Set((float)$xml->ticksMajor, (float)$xml->ticksMinor); | 
|---|
|  | 109 | } | 
|---|
|  | 110 | $g->xaxis->SetLabelFormat('%1.1f'); | 
|---|
|  | 111 | $g->xaxis->SetFont(FF_TREBUCHE, FS_NORMAL, 9); | 
|---|
|  | 112 | $g->xgrid->Show(true); | 
|---|
|  | 113 | $g->yaxis->HideZeroLabel(); | 
|---|
|  | 114 | $g->yaxis->SetFont(FF_TREBUCHE, FS_NORMAL, 9); | 
|---|
|  | 115 | $g->ygrid->SetFill(true,'#EFEFEF@0.5','#FFFFFF@0.5'); | 
|---|
|  | 116 | if (!empty($this->title)) | 
|---|
|  | 117 | { | 
|---|
|  | 118 | $g->title->Set($this->title); | 
|---|
|  | 119 | $g->title->SetColor("red"); | 
|---|
|  | 120 | $g->title->SetFont( FF_FONT2, FS_BOLD); | 
|---|
|  | 121 | } | 
|---|
|  | 122 | $xml = simplexml_load_file("data/$this->style.xml"); | 
|---|
|  | 123 |  | 
|---|
|  | 124 |  | 
|---|
|  | 125 | foreach ($xml->percentile as $p) { | 
|---|
|  | 126 |  | 
|---|
|  | 127 | $percentile = $p->label; | 
|---|
|  | 128 | $yp = array(); | 
|---|
|  | 129 |  | 
|---|
|  | 130 | foreach ($p->value as $value) { | 
|---|
|  | 131 | $yp[] = (float)$value; | 
|---|
|  | 132 | } | 
|---|
|  | 133 |  | 
|---|
|  | 134 | // Create the spline | 
|---|
|  | 135 | $spline = new Spline($xdata, $yp); | 
|---|
|  | 136 |  | 
|---|
|  | 137 | // Get smoothed points | 
|---|
|  | 138 | list($newx, $newy) = $spline->Get(100); | 
|---|
|  | 139 |  | 
|---|
|  | 140 | $lplot = new LinePlot($newy, $newx); | 
|---|
|  | 141 | $lplot->SetColor('#CCCCCC'); | 
|---|
|  | 142 |  | 
|---|
|  | 143 | if ($percentile == '50') | 
|---|
|  | 144 | { | 
|---|
|  | 145 | $lplot->SetColor('#666666'); | 
|---|
|  | 146 | } | 
|---|
|  | 147 |  | 
|---|
|  | 148 | // Add the plots to the graph and stroke | 
|---|
|  | 149 | $g->Add($lplot); | 
|---|
|  | 150 |  | 
|---|
|  | 151 | // Add percentile label to graph | 
|---|
|  | 152 | $txt = new Text($percentile . ($percentile == '3' ? 'rd' : 'th')); | 
|---|
|  | 153 | $txt->SetScalePos($xdata[sizeof($xdata)-1]+(float)$xml->percentileXNudge,$yp[sizeof($yp)-1]+(float)$xml->percentileYNudge); | 
|---|
|  | 154 | $txt->SetColor('#666666'); | 
|---|
|  | 155 | $txt->SetFont(FF_TREBUCHE, FS_NORMAL, 9); | 
|---|
|  | 156 | $g->AddText($txt); | 
|---|
|  | 157 | } | 
|---|
|  | 158 |  | 
|---|
|  | 159 | if (!empty($this->patientXarray) && !empty($this->patientYarray) && sizeof($this->patientXarray) == sizeof($this->patientYarray)) | 
|---|
|  | 160 | { | 
|---|
|  | 161 | $patientPlot = new LinePlot($this->patientYarray, $this->patientXarray); | 
|---|
|  | 162 | $patientPlot->SetColor('orange'); | 
|---|
|  | 163 | $patientPlot->SetWeight(3); | 
|---|
|  | 164 | $patientPlot->value->Show(); | 
|---|
|  | 165 | $patientPlot->value->SetColor('brown'); | 
|---|
|  | 166 | $patientPlot->value->SetFont(FF_COURIER, FS_BOLD); | 
|---|
|  | 167 | $patientPlot->value->SetAlign('left', 'top'); | 
|---|
|  | 168 | $patientPlot->value->SetMargin(-5); | 
|---|
|  | 169 | $patientPlot->mark->SetType(MARK_DIAMOND); | 
|---|
|  | 170 | $patientPlot->mark->SetWidth(7); | 
|---|
|  | 171 | $patientPlot->mark->SetColor('orange'); | 
|---|
|  | 172 | $patientPlot->mark->SetFillColor('red'); | 
|---|
|  | 173 |  | 
|---|
|  | 174 | $g->Add($patientPlot); | 
|---|
|  | 175 | } | 
|---|
|  | 176 |  | 
|---|
|  | 177 | $g->Stroke(); | 
|---|
|  | 178 | } | 
|---|
|  | 179 | } | 
|---|
|  | 180 |  | 
|---|
|  | 181 | ?> | 
|---|