@@ -74,6 +74,7 @@ class Cartesian(Widget):
7474 :param int nudge_y: movement in pixels in the y direction to move the origin.
7575 Defaults to 0
7676
77+ :param bool verbose: print debugging information in some internal functions. Default to False
7778
7879 **Quickstart: Importing and using Cartesian**
7980
@@ -181,11 +182,14 @@ def __init__(
181182 subticks : bool = False ,
182183 nudge_x : int = 0 ,
183184 nudge_y : int = 0 ,
185+ verbose : bool = False ,
184186 ** kwargs ,
185187 ) -> None :
186188
187189 super ().__init__ (** kwargs )
188190
191+ self ._verbose = verbose
192+
189193 self ._background_color = background_color
190194
191195 self ._axes_line_color = axes_color
@@ -250,8 +254,8 @@ def __init__(
250254 self ._axesy_bitmap = displayio .Bitmap (self ._axesy_width , self .height , 4 )
251255 self ._axesy_bitmap .fill (0 )
252256
253- self ._screen_bitmap = displayio .Bitmap (self .width , self .height , 5 )
254- self ._screen_bitmap . fill ( 5 )
257+ self ._plot_bitmap = displayio .Bitmap (self .width , self .height , 5 )
258+ self .clear_plot_lines ( )
255259 self ._screen_palette = displayio .Palette (6 )
256260 self ._screen_palette .make_transparent (0 )
257261 self ._screen_palette [1 ] = self ._tick_color
@@ -293,7 +297,7 @@ def __init__(
293297 )
294298
295299 self ._screen_tilegrid = displayio .TileGrid (
296- self ._screen_bitmap ,
300+ self ._plot_bitmap ,
297301 pixel_shader = self ._screen_palette ,
298302 x = 0 ,
299303 y = 0 ,
@@ -310,8 +314,6 @@ def __init__(
310314 self .append (self ._screen_tilegrid )
311315 self .append (self ._corner_tilegrid )
312316
313- self ._update_line = True
314-
315317 self ._pointer = None
316318 self ._circle_palette = None
317319 self .plot_line_point = None
@@ -389,10 +391,12 @@ def _draw_ticks(self) -> None:
389391
390392 if self ._subticks :
391393 if i in subticks :
394+ # calc subtick_line_height; force min lineheigt to 1.
395+ subtick_line_height = max (1 , self ._tick_line_height // 2 )
392396 rectangle_helper (
393397 text_dist ,
394398 self ._axes_line_thickness ,
395- self . _tick_line_height // 2 ,
399+ subtick_line_height ,
396400 1 ,
397401 self ._axesx_bitmap ,
398402 1 ,
@@ -457,6 +461,130 @@ def _draw_pointers(self, x: int, y: int) -> None:
457461
458462 self .append (self ._pointer )
459463
464+ def _calc_local_xy (self , x : int , y : int ) -> (int , int ):
465+ local_x = (
466+ int ((x - self ._xrange [0 ]) * self ._factorx * self ._valuex ) + self ._nudge_x
467+ )
468+ # details on `+ (self.height - 1)` :
469+ # the bitmap is set to self.width & self.height
470+ # but we are only allowed to draw to pixels 0..height-1 and 0..width-1
471+ local_y = (
472+ int ((self ._yrange [0 ] - y ) * self ._factory * self ._valuey )
473+ + (self .height - 1 )
474+ + self ._nudge_y
475+ )
476+ return (local_x , local_y )
477+
478+ def _check_local_x_in_range (self , local_x ):
479+ return 0 <= local_x < self .width
480+
481+ def _check_local_y_in_range (self , local_y ):
482+ return 0 <= local_y < self .height
483+
484+ def _check_local_xy_in_range (self , local_x , local_y ):
485+ return self ._check_local_x_in_range (local_x ) and self ._check_local_y_in_range (
486+ local_y
487+ )
488+
489+ def _check_x_in_range (self , x ):
490+ return self ._xrange [0 ] <= x <= self ._xrange [1 ]
491+
492+ def _check_y_in_range (self , y ):
493+ return self ._yrange [0 ] <= y <= self ._yrange [1 ]
494+
495+ def _check_xy_in_range (self , x , y ):
496+ return self ._check_x_in_range (x ) and self ._check_y_in_range (y )
497+
498+ def _add_point (self , x : int , y : int ) -> None :
499+ """_add_point function
500+ helper function to add a point to the graph in the plane
501+ :param int x: ``x`` coordinate in the local plane
502+ :param int y: ``y`` coordinate in the local plane
503+ :return: None
504+ rtype: None
505+ """
506+ local_x , local_y = self ._calc_local_xy (x , y )
507+ if self ._verbose :
508+ print ("" )
509+ print (
510+ "xy: ({: >4}, {: >4}) "
511+ "_xrange: ({: >4}, {: >4}) "
512+ "_yrange: ({: >4}, {: >4}) "
513+ "" .format (
514+ x ,
515+ y ,
516+ self ._xrange [0 ],
517+ self ._xrange [1 ],
518+ self ._yrange [0 ],
519+ self ._yrange [1 ],
520+ )
521+ )
522+ print (
523+ "local_*: ({: >4}, {: >4}) "
524+ " width: ({: >4}, {: >4}) "
525+ " height: ({: >4}, {: >4}) "
526+ "" .format (
527+ local_x ,
528+ local_y ,
529+ 0 ,
530+ self .width ,
531+ 0 ,
532+ self .height ,
533+ )
534+ )
535+ if self ._check_xy_in_range (x , y ):
536+ if self ._check_local_xy_in_range (local_x , local_y ):
537+ if self .plot_line_point is None :
538+ self .plot_line_point = []
539+ self .plot_line_point .append ((local_x , local_y ))
540+ else :
541+ # for better error messages we check in detail what failed...
542+ # this should never happen:
543+ # we already checked the range of the input values.
544+ # but in case our calculation is wrong we handle this case to..
545+ if not self ._check_local_x_in_range (local_x ):
546+ raise ValueError (
547+ "local_x out of range: "
548+ "local_x:{: >4}; _xrange({: >4}, {: >4})"
549+ "" .format (
550+ local_x ,
551+ 0 ,
552+ self .width ,
553+ )
554+ )
555+ if not self ._check_local_y_in_range (local_y ):
556+ raise ValueError (
557+ "local_y out of range: "
558+ "local_y:{: >4}; _yrange({: >4}, {: >4})"
559+ "" .format (
560+ local_y ,
561+ 0 ,
562+ self .height ,
563+ )
564+ )
565+ else :
566+ # for better error messages we check in detail what failed...
567+ if not self ._check_x_in_range (x ):
568+ raise ValueError (
569+ "x out of range: "
570+ "x:{: >4}; xrange({: >4}, {: >4})"
571+ "" .format (
572+ x ,
573+ self ._xrange [0 ],
574+ self ._xrange [1 ],
575+ )
576+ )
577+ if not self ._check_y_in_range (y ):
578+ raise ValueError (
579+ "y out of range: "
580+ "y:{: >4}; yrange({: >4}, {: >4})"
581+ "" .format (
582+ y ,
583+ self ._yrange [0 ],
584+ self ._yrange [1 ],
585+ )
586+ )
587+
460588 def update_pointer (self , x : int , y : int ) -> None :
461589 """updater_pointer function
462590 helper function to update pointer in the plane
@@ -465,46 +593,49 @@ def update_pointer(self, x: int, y: int) -> None:
465593 :return: None
466594 rtype: None
467595 """
468- local_x = int ((x - self ._xrange [0 ]) * self ._factorx ) + self ._nudge_x
469- local_y = (
470- int ((self ._yrange [0 ] - y ) * self ._factory ) + self .height + self ._nudge_y
471- )
596+ self ._add_point (x , y )
597+ if not self ._pointer :
598+ self ._draw_pointers (
599+ self .plot_line_point [- 1 ][0 ],
600+ self .plot_line_point [- 1 ][1 ],
601+ )
602+ else :
603+ self ._pointer .x = self .plot_line_point [- 1 ][0 ]
604+ self ._pointer .y = self .plot_line_point [- 1 ][1 ]
472605
473- if local_x >= 0 or local_y <= 100 :
474- if self ._update_line :
475- self ._draw_pointers (local_x , local_y )
476- self ._update_line = False
477- else :
478- self ._pointer .x = local_x
479- self ._pointer .y = local_y
606+ def add_plot_line (self , x : int , y : int ) -> None :
607+ """add_plot_line function.
480608
481- def _set_plotter_line ( self ) -> None :
482- self . plot_line_point = []
609+ add line to the plane.
610+ multiple calls create a line-plot graph.
483611
484- def update_line (self , x : int , y : int ) -> None :
485- """updater_line function
486- helper function to update pointer in the plane
487612 :param int x: ``x`` coordinate in the local plane
488613 :param int y: ``y`` coordinate in the local plane
489614 :return: None
615+
490616 rtype: None
491617 """
492- local_x = int ((x - self ._xrange [0 ]) * self ._factorx ) + self ._nudge_x
493- local_y = (
494- int ((self ._yrange [0 ] - y ) * self ._factory ) + self .height + self ._nudge_y
495- )
496- if x < self ._xrange [1 ] and y < self ._yrange [1 ]:
497- if local_x > 0 or local_y < 100 :
498- if self ._update_line :
499- self ._set_plotter_line ()
500- self .plot_line_point .append ((local_x , local_y ))
501- self ._update_line = False
502- else :
503- bitmaptools .draw_line (
504- self ._screen_bitmap ,
505- self .plot_line_point [- 1 ][0 ],
506- self .plot_line_point [- 1 ][1 ],
507- local_x ,
508- local_y ,
509- 1 ,
510- )
618+ self ._add_point (x , y )
619+ if len (self .plot_line_point ) > 1 :
620+ bitmaptools .draw_line (
621+ self ._plot_bitmap ,
622+ self .plot_line_point [- 2 ][0 ],
623+ self .plot_line_point [- 2 ][1 ],
624+ self .plot_line_point [- 1 ][0 ],
625+ self .plot_line_point [- 1 ][1 ],
626+ 1 ,
627+ )
628+
629+ def clear_plot_lines (self , palette_index = 5 ):
630+ """clear_plot_lines function.
631+
632+ clear all added lines
633+ (clear line-plot graph)
634+
635+ :param int palette_index: color palett index. Defaults to 5
636+ :return: None
637+
638+ rtype: None
639+ """
640+ self .plot_line_point = None
641+ self ._plot_bitmap .fill (palette_index )
0 commit comments