Skip to content

Add cartesian widget #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Apr 5, 2021
Merged

Add cartesian widget #22

merged 39 commits into from
Apr 5, 2021

Conversation

jposada202020
Copy link
Contributor

@jposada202020 jposada202020 commented Mar 21, 2021

Purpose of this PR is to include a Cartesian Plane to the DisplaIO layout. This will help to plot values in a (x,y) form.
Inspired by the Dial Widget from @kmatch98

image

52snhb

image

@jposada202020 jposada202020 added the enhancement New feature or request label Mar 21, 2021
@jposada202020 jposada202020 self-assigned this Mar 21, 2021
@kmatch98
Copy link
Contributor

Wow, this is cool. I took a brief look at this (but haven’t run it on hardware yet) and a couple of items for discussion and consideration. (Feel free to disagree with any of this. I always think having something that meets the majority of the needs is good to get in place so people can get use out of it, and then you can always optimize later if needed.)

I’m curious how you think this will be used. I could imagine that one widget is the two axes (or maybe two separate “axis” widgets?) and a separate widget is the actual data graph. If we keep the axes and graph data as separate items then you can separately update the data graph without it messing up your axes bitmap.

Also, I’d consider evaluating the vectorio library for your axes. It has tools for drawing rectangles, so you could possibly use vectorio for your axes and tick marks. I haven’t done a direct comparison in meters use between a bitmap and vectorio but that could be an option.

As for the other details, it looks like the tick marks aren’t evenly distributed. Also adding labels will be useful now that you have rotation labels working! This will be a great addition. As soon as you offer folks two axes, next they will want plots. That is progress!

@kmatch98
Copy link
Contributor

One other thing to mention added a bitmaptools.draw_line function. https://circuitpython.readthedocs.io/en/latest/shared-bindings/bitmaptools/index.html#bitmaptools.draw_line

If you use a bitmap for the axes, I think it will be better to use draw_line rather than the rotozoom ( I need to update this in Dial too).

If the line has a stroke > 1 you will need to write mutiple times with bitmaptools.draw_line to make the line wider, maybe writing a rectangle function would be useful for a lot of uses.

@jposada202020
Copy link
Contributor Author

jposada202020 commented Mar 21, 2021

Wow, this is cool. I took a brief look at this (but haven’t run it on hardware yet) and a couple of items for discussion and consideration. (Feel free to disagree with any of this. I always think having something that meets the majority of the needs is good to get in place so people can get use out of it, and then you can always optimize later if needed.)

I’m curious how you think this will be used. I could imagine that one widget is the two axes (or maybe two separate “axis” widgets?) and a separate widget is the actual data graph. If we keep the axes and graph data as separate items then you can separately update the data graph without it messing up your axes bitmap.

Also, I’d consider evaluating the vectorio library for your axes. It has tools for drawing rectangles, so you could possibly use vectorio for your axes and tick marks. I haven’t done a direct comparison in meters use between a bitmap and vectorio but that could be an option. See 185e539

As for the other details, it looks like the tick marks aren’t evenly distributed. Also adding labels will be useful now that you have rotation labels working! This will be a great addition. As soon as you offer folks two axes, next they will want plots. That is progress! 5af4bf2

Uses

I think the best use is to plot values vs time, as MU, Arduino , maybe we can add line and other types of things.
Two widgets, that is a good idea, at the beginning I was thinking as an level bar, but then I thought we have already the progress bar, and we can spin that one. But I like it. and I am open. See e8e67c0

Vectorio

Yes, I have not tried that when I was doing the ticks, but if you see the new version I am using vectorio for the pointer, so that is perfect I will take a look into that. See 057a96c

Ticks

Yes, ticks, I think the best think is to create a "screen" factor to evenly distribute them. I will add that for sure, thanks for the recommendation. see a36b27c

Axes lines

Thanks, I did not know that, for sure I will change that. Thanks for the recommendations.

Tests

I know is bare bones but please try the last commit with the example provided, now you can add the position, the dimensions and animate the pointer. I will work on this and all your recommendations.

All recommendations are welcome, thanks

# TODO Replace with drawline/vectorio           [ ]
# TODO Make a rectangle function                [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Replace with drawline/vectorio           [ ]
# TODO Make a rectangle function                [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Replace with drawline/vectorio           [ ]
# TODO Make a rectangle function                [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Make a rectangle function                [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO Include functions to equal space ticks   [ ]
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
@jposada202020 jposada202020 changed the title Initial changes to include cartesian widget Add cartesian widget Mar 22, 2021
# TODO Make labels and text                     [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO ticks evenly distributed                 [√]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO Updater to use local coordinates         [ ]
# TODO Make Styles applicable                   [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [ ]
# TODO Updater to use local coordinates         [ ]
# TODO Animate when overflow                    [ ]
# TODO Add Subticks functionality               [√]
# TODO Updater to use local coordinates         [√]
@jposada202020 jposada202020 marked this pull request as ready for review March 23, 2021 02:18
@jposada202020
Copy link
Contributor Author

This is ready for review, after feedback and changes I will work on the plot moving with the data. Thanks

@kmatch98
Copy link
Contributor

Wow the graphics are looking good. I’m excited to see all the graphs that I can make with it. I am getting the matplotlib vibes here too! I’ll spend some time tomorrow on this one.

@kmatch98
Copy link
Contributor

This is looking really good. Most of what I have is just minor tweaks. Only a couple things are "must-do" and the rest can are considered cleanup.

Note: I did all my testing with the simpletest version.

Must-do:

  • Using the pointer: (0,0) doesn't seem to go through the origin. (10,0) is correctly on the x-axis. But (0,10) isn't on the y-axis. Somehow the vertical and horizontal distance to the first tick mark don't seem to be the same.
  • major_tick_stroke value is ignored
  • pointer_radiusvalue is ignored

Tweaks:

  • The y-axis width seems to be one-pixel wider than the x-axis width. You can use bitmaptools.fill_region for drawing all the lines/rectangles. in _init_.rectangle_helper:
	    if bitmaptool:
        	bitmaptools.fill_region(bitmap, x0, y0, x0+width-1, y0+height-1, color_index)

I don't think it's necessary to use draw_line for one case and rectangle_helper for others, they can all use one approach.

  • The doc strings say axesx_range, the variable name is xrange and yrange
  • What should be drawn for the pointer if it is outside the graph range? Maybe give a warning and plot nothing?
  • display_color maybe is better called as background or background_color?
  • If major_tick_length is a large number, it goes out of range of the bitmap and an error is raised. Should the code calculate the major_tick_length into the size of the bitmaps?

This is a great addition. I can already envision new subclasses for all different kinds of graphs.

@jposada202020
Copy link
Contributor Author

@kmatch98
Thank again for reviewing and given all these feedback.

  1. Using the pointer: (0,0) doesn't seem to go through the origin. (10,0) is correctly on the x-axis. corrected the position for the Y axis, now the pointer and the ticks will show in the correct position.
  2. major_tick_stroke value is ignored. Corrected
  3. pointer_radiusvalue is ignored. Corrected.
  4. You can use bitmaptools.fill_region. I change the code and the function to only use bitmaptools.fill with the rectangle helper, slightly modified from your suggestion
  5. Dosctrings corrected on the Xrange usage, change the name of the variable display_color, and add the graphs and gifs to the docs
  6. Added checks for value range in both tick thickness and tick length.

This is a great addition. I can already envision new subclasses for all different kinds of graphs. Thank you. me too this is a lot of fun :)

@jposada202020
Copy link
Contributor Author

@i built locallly the docs and they work, however a second check would not hurt. thanks.

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Mar 26, 2021

@jposada202020 I am trying this out tonight. I think there may be an issue with ticks and axes lines that use 1px stroke width.

In the simpletest the tick stroke size is 1 pixel and the are not shown:

image

I modified the example to use 1px for the axes stroke as well and I see similar results where those lines don't get drawn.

I do see many images above with the 1px lines though so I suspect maybe this is from a more recent change.

Copy link
Contributor

@FoamyGuy FoamyGuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome @jposada202020. Thanks for working on this!

I noticed a small issue, and have a few suggested improvements in the simpletest.

@@ -247,6 +247,24 @@ def __init__(
self._screen_palette[4] = 0xFFFFFF
self._screen_palette[5] = self._background_color

self._corner_bitmap = displayio.Bitmap(10, 10, 5)
Copy link
Contributor Author

@jposada202020 jposada202020 Mar 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FoamyGuy Here is the inclusion to solve the corner issue, I tested with different strokes, however a second pair of eyes would not hurt

@jposada202020
Copy link
Contributor Author

I resolve the issue with the corner, I was trying to create another bitmap to fill it, to tell the truth, other options will not work, as all the logic to convert from scale, to pixel to range is bases on the position of the [0,0] coordinates, and the widget is coordinates starts above. But maybe there is other ideas, but always open to new suggestions :) Thank you @FoamyGuy for the recommendations, and suggestions and for taking the time, to verify this.

:return: None
rtype: None
"""
local_x = int((x - self._xrange[0]) * self._factorx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I experimented a bit with the pointer position to try to get 0,0 matching the bottom left corner.
I updated this line like this:

local_x = int((x - self._xrange[0]) * self._factorx) - 2

and it seems to be lining up correctly for me like this in a few quick tests. Do you think this would cause trouble in some situations @jposada202020? or would it be an okay fix to use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FoamyGuy I think is perfect, doing the equalizer I realized that we need a buffer to correct all the float to int conversion, I think it is perfect, errors will be added at the end, kmatch uses a nudge variable to do this. Maybe following this line of thought instead of adding the 2 we could add the nudge correction, what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jposada202020 That sounds good to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FoamyGuy Thanks, I add the nudge parameter

@FoamyGuy
Copy link
Contributor

I think we need to use the nudge parameters inside update_point() function so that they can be used to move the pointer a little bit.

@jposada202020
Copy link
Contributor Author

You are right. I did not put it in the update function.

@FoamyGuy
Copy link
Contributor

FoamyGuy commented Apr 3, 2021

I think there may be an off by one issue with the stroke size. The current simpletest has this:

major_tick_stroke=1,  # ticks width in pixels

But when it runs there are no ticks drawn on the display:
image

I noticed similar behavior with axes_stroke as well. If you set it to 1 then the axes lines will not get drawn.

@jposada202020
Copy link
Contributor Author

Corrected and tested with Axes=1 and ticks=1. Thanks for reviewing @FoamyGuy

Copy link
Contributor

@FoamyGuy FoamyGuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested out the latest version and it's working well for me. Thanks for all of your work on this @jposada202020.

I found one reference to the style function that was removed in the advanced example. Once that is taken care of I think this will be ready to merge.

Copy link
Contributor

@FoamyGuy FoamyGuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Tested successfully with:

Adafruit CircuitPython 6.2.0-rc.0 on 2021-04-01; Adafruit PyPortal with samd51j20

Thanks for this great new widget @jposada202020. I'm excited to see what kinds of charts folks use it for!

@FoamyGuy FoamyGuy merged commit d05ed7d into adafruit:main Apr 5, 2021
@jposada202020 jposada202020 deleted the cartesian branch April 5, 2021 03:01
adafruit-adabot added a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Apr 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants