Commits

Virgil Dupras committed 13518b6

[#352 state:fixed] Fixed glitch in bar graph's xaxis drawing.

Comments (0)

Files changed (3)

core/gui/bar_graph.py

 
 class BarGraph(Graph):
     # BarGraph's data point is (float x1, float x2, float past_value, float future_value).
-    #--- Virtual
-    def _currency(self):
-        return None
-    
-    def _get_cash_flow(self, date_range):
-        return 0
-    
-    #--- Override
-    def compute_data(self):
+    #--- Private
+    def _bar_periods(self):
         def monthly_period(start_date):
             return MonthRange(start_date)
         
             period_end = period_start + timedelta(6)
             return DateRange(period_start, period_end)
         
-        TODAY = date.today()
         date_range = self.document.date_range
-        self._data = []
-        self._min_date = date_range.start
-        self._max_date = date_range.end
         period_getter = monthly_period if date_range.days >= 100 else weekly_period
         current_date = date_range.start
         while current_date <= date_range.end:
             period = period_getter(current_date)
             if isinstance(date_range, YearToDateRange): # we don't overflow in YTD
-                period.end = min(period.end, self._max_date)
-            self._min_date = min(period.start, self._min_date)
-            self._max_date = max(period.end + timedelta(1), self._max_date)
+                period.end = min(period.end, date_range.end)
+            yield period
             current_date = period.end + timedelta(1)
+    
+    #--- Virtual
+    def _currency(self):
+        return None
+    
+    def _get_cash_flow(self, date_range):
+        return 0
+    
+    #--- Override
+    def compute_data(self):
+        TODAY = date.today()
+        self._data = []
+        for period in self._bar_periods():
             if TODAY in period:
                 past_amount = float(self._get_cash_flow(period.past))
                 future_amount = float(self._get_cash_flow(period.future))
                 self._data.append((left + padding, right - padding, past_amount, future_amount))
     
     def compute_x_axis(self):
-        Graph.compute_x_axis(self)
-        self.xmin = self._offset_xpos(self._min_date.toordinal())
-        self.xmax = self._offset_xpos(self._max_date.toordinal())
+        date_range = self.document.date_range
+        min_date = date_range.start
+        max_date = date_range.end
+        for period in self._bar_periods():
+            min_date = min(period.start, min_date)
+            max_date = max(period.end + timedelta(1), max_date)
+        Graph.compute_x_axis(self, min_date=min_date, max_date=max_date)
     
     def yrange(self):
         if self._data:

core/gui/graph.py

         return xpos - self._xoffset
     
     #--- Public    
-    def compute_x_axis(self):
+    def compute_x_axis(self, min_date=None, max_date=None):
+        # By default, xmin and xmax are determined by date range's start and end, but you can
+        # override that by specifying min_date and max_date.
         date_range = self.document.date_range
-        self.xmin = self._offset_xpos(date_range.start.toordinal())
-        self.xmax = self._offset_xpos(date_range.end.toordinal() + 1)
+        if min_date is None:
+            min_date = date_range.start
+        if max_date is None:
+            max_date = date_range.end
+        # Our X data is based on ordinal date values, which can be quite big. On Qt, we get some
+        # weird overflow problem when translating our painter by this large offset. Therefore, it's
+        # better to offset this X value in the model.
+        self._xoffset = min_date.toordinal()
+        self.xmin = self._offset_xpos(min_date.toordinal())
+        self.xmax = self._offset_xpos(max_date.toordinal() + 1)
         tick = date_range.start
         self.xtickmarks = [self._offset_xpos(tick.toordinal())]
         self.xlabels = []
         self.ylabels = [dict(text=str(x), pos=x) for x in self.ytickmarks]
 
     def compute(self):
-        # Our X data is based on ordinal date values, which can be quite big. On Qt, we get some
-        # weird overflow problem when translating our painter by this large offset. Therefore, it's
-        # better to offset this X value in the model.
-        self._xoffset = self.document.date_range.start.toordinal()
+        # The order in which we compute axis and data is important. We start with the xaxis because
+        # this is what will give us our xoffset, which is then used in compute_data() to offset
+        # our data points. Then, we compute data before the yaxis because we need the data to know
+        # how big our yaxis is.
+        self.compute_x_axis()
         self.compute_data()
-        self.compute_x_axis()
         self.compute_y_axis()
     
     def draw_graph(self, context):

core/tests/main_test.py

     def test_xaxis_on_month_range(self, app):
         # The xaxis min/max follow the date range overflows
         start = date(2008, 1, 1)
+        app.doc.first_weekday = 0
+        # The month of Jan 2008 has a monday on the 31st of december and another on the 4th of
+        # january. All of this is 5 weeks (35 days)
         app.doc.date_range = MonthRange(start)
-        eq_(app.bargraph.xmin, date(2007, 12, 31).toordinal() - start.toordinal())
-        eq_(app.bargraph.xmax, date(2008, 2, 4).toordinal() - start.toordinal())
+        eq_(app.bargraph.xmin, 0)
+        # We add +1 to the xaxis' max date
+        eq_(app.bargraph.xmax, 35+1)
     
 
 class TestFourEntriesInRange: