-
-
Notifications
You must be signed in to change notification settings - Fork 377
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
feat(barchart): enable barchart groups #288
Conversation
I'm not sure how this compares to current barchart, implementation wise, but maybe it could be solved by adding a method/flag to the current barchart, instead of introducing a new widget? |
true I changed the old barchart. it should be backwards compatible |
Codecov Report
@@ Coverage Diff @@
## main #288 +/- ##
==========================================
+ Coverage 83.11% 83.80% +0.68%
==========================================
Files 37 39 +2
Lines 7717 8031 +314
==========================================
+ Hits 6414 6730 +316
+ Misses 1303 1301 -2
|
I like the idea and direction - perhaps consider documenting the user's perspective a little before continuing into the code. (It's important to tell us what you want to do, so that when it's complete, it's obvious). I notice that this adds a new "Group" feature, but "Group" only appears in the API once. How would you design the API so that it made this feature more explicitly obvious? I think it's probably possible to keep the single Can you please make an issue for this to discuss the functionality of the new feature? (Would be nice to get a few more eyes on it). |
true. the problem with possible Solutions:
the following 2 code sections produces the same result:
done |
92fe909
to
f8b85f1
Compare
e2eef3d
to
6c1f4fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there. I have some concerns around the size of the new render method, and the lack of docs / new unit tests. I'm liking where this is heading though.
dcb9d07
to
15ec280
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving the bar printing into it's own method helped quite a bit with readability. Dropped a couple thoughts on how render
could be further split up / shortened as well as some nitpicks.
Additionally you could also move the label printing (group and bar) in another (or other) method(s).
Finally you have a little bug in your example where the bar colors are applied to parts of the legend's border.
ca7abe4
to
be2cdc5
Compare
this is feature not a bug 😄 . But it is fixed. (there still is another hidden small bug in the legend 😸, but this MR is about the BarChart ) I renamed |
There's two approaches to not rendering specific bars, truncating them before rendering, or filtering them after. The truncate approach seems more difficult to reason about as it changes fields outside of the method to communicate with other methods. (This is like Alice calling Bob on the phone to tell him something then calling Carol and asking her to ask Bob for the information just provided) I think I can sort of see how the code landed there, but the following general approach (using a remaining area Rect to render the bar / group into) might help make this code clearer: let remaining_area = area;
for group in data {
if too_small_for_a_group(remaining_area) {
break;
}
render_group(&group, &mut remaining_area);
}
fn render_group(group &Group, &mut remaining_area: Rect) {
render_group_label(...);
for bar in group.bars {
if too_small_for_any_bar(remaining_area) {
break;
}
render_bar(bar, &mut remaining_area);
}
remaining_area = Rect { x: remaining_area.x + group_gap)
}
fn render_bar() {
let bar_area = ...
let label_area = ...
let value_area = ...
render_bar_main_part(bar, bar_area);
render_label(bar, label_area);
render_value(...);
let w = bar_width + bar_gap;
*remaining_area = remaining_area {x: remaining_area + bar_width + bar_gap, ...}
} |
168ca54
to
4a24730
Compare
Preprocessing data before working on it, is very common approach. I don't think the Alice bob and Carol example is very accurate 😄 .
you are suggesting a third method, which is in my opinion worse than the truncate and filtering methods, which are both very similar. here my comparison:
preprocess the data once. afterwards there is no chance that you are working on the wrong data, because they simply doesn't exist. There is in total 4 places where we must filter. (in the future maybe more)
the original code had 2 loops, we need to filter twice. if someone adds a 3. loop, the chances are high, that he will forget about filtering. with this patch we need to filter the bars too, which makes this method a little bit harder to implement. now we need to filter 2 nested loops in 2 different functions. I can't see any reason why this method is superior then preprocesing the data first
every time you draw, you need to check, if there is enough space. I see 2 drawbacks. the first one: the check logic will needs to be duplicated at least twice. when printing the bars and later when printing the labels. the second drawback: this check will be executed in
I would rather to filter or preprocess the data, than checking in every iteration, whether there is enough space. and the problem get worse with every additional loop. (code duplication) till now you improved the code immensely, the length of that method became very short. I think most developers will understand it. 😄 |
The concept that's at play here is https://en.wikipedia.org/wiki/Action_at_a_distance_%28computer_programming%29.
The third method seems like it would lead to a simpler and more obvious solution with generally shorter methods that just do one thing. The difference in my mind is doing things in batches (calculate, render bars, render labels) vs doing things one by one in a nested fashion. In the batch approach, you have to understand how each part affects the whole, whereas the individual nested approach the interaction between the pieces is right there.
This is a problem only because the rendering of the bars and labels is separate - if bars and their label / value are rendered at the same time then this isn't a problem.
This check happens already, it just happens within the delete invisible method. P.s. Happy to fix this later if the code seems reasonably obvious to @mindoodoo as is. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved Subject to @mindoodoo's review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM ! Thanks for the PR !
Example: to show the revenue of different companies: ┌────────────────────────┐ │ ████ │ │ ████ │ │ ████ ████ │ │ ▄▄▄▄ ████ ████ ████ │ │ ████ ████ ████ ████ │ │ ████ ████ ████ ████ │ │ █50█ █60█ █90█ █55█ │ │ Mars April │ └────────────────────────┘ new structs are introduced: Group and Bar. the data function is modified to accept "impl Into<Group<'a>>". a new function "group_gap" is introduced to set the gap between each group unit test changed to allow the label to be in the center Signed-off-by: Ben Fekih, Hichem <[email protected]>
The bar labels are currently printed string from the left side of bar. This commit centers the labels under the bar. Signed-off-by: Ben Fekih, Hichem <[email protected]>
Merged! Thanks for your contribution @karthago1 |
@joshka and @mindoodoo thank you too for your help and patience 😄 . I can't wait to switch to the crate.io ratatui version at work. The use case we have is to show the operating hours of multiple temperature sensors in different temperature ranges:
the only think I wish to do, but I don't know if it is possible, is to write the numbers vertically. (instead of horizontally) |
* feat(barchart): allow to add a group of bars Example: to show the revenue of different companies: ┌────────────────────────┐ │ ████ │ │ ████ │ │ ████ ████ │ │ ▄▄▄▄ ████ ████ ████ │ │ ████ ████ ████ ████ │ │ ████ ████ ████ ████ │ │ █50█ █60█ █90█ █55█ │ │ Mars April │ └────────────────────────┘ new structs are introduced: Group and Bar. the data function is modified to accept "impl Into<Group<'a>>". a new function "group_gap" is introduced to set the gap between each group unit test changed to allow the label to be in the center Signed-off-by: Ben Fekih, Hichem <[email protected]> * feat(barchart)!: center labels by default The bar labels are currently printed string from the left side of bar. This commit centers the labels under the bar. Signed-off-by: Ben Fekih, Hichem <[email protected]> --------- Signed-off-by: Ben Fekih, Hichem <[email protected]>
I modified the barchart to support adding multiple bars from different data set
see the the following image:
if this feature is needed, then I can continue and write some unit tests