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
Grouped Bar Chart #29
Comments
Thanks for the note! General info on scalesThe four included scales can pretty much be used however you want. The If it sounds weird to use a value called <Layecake
custom={{
x1: scaleOrdinal().domain(YOUR_DOMAIN).range(YOUR_RANGE)
}}
...
> The x, y, r and z scales are generally more useful because they are passed in default ranges based on the calculated width and height. Info on grouped and stacked chartsI've never had occasion to make one of these charts so you'd have to experiment what the best architecture is within the svelte context. Looking briefly at the example, it seems to use the bandwidth of Instead of creating these scales on the <script>
import { getContext } from 'svelte';
import { scaleBand } from 'd3-scale';
const { width, data } = getContext('LayerCake');
const keys = $data.columns.slice(1);
const x0 = scaleBand()
.domain($data.map(d => d[groupKey])) // this should be in some kind of function to determine the `groupKey`
.rangeRound([0, $width])
.paddingInner(0.1);
const x1 = scaleBand()
.domain(keys)
.rangeRound([0, x0.bandwidth()])
.padding(0.05)
</script>
<!-- Components go here --> Hope that helps point you in the right direction. Let me know what you come up with! |
Thanks @mhkeller! Good information. Initially focused on a grouped (non-stacked) bar chart but was curious how that would transition to including stacking (if needed). Let me play around with LayerCake more and I'll let you know. |
Sounds good. The stacking would be easy to add on since the D3 stack layout function builds the stacking information into the structure of your data, as opposed to requiring a separate scale to handle the offset. |
Btw, I was comparing the difference between Rich's I have some hierarchy examples I've been making in with React / vx / react-spring but likely going to switch over to Svelte and continue that work. Actually started it a few weeks ago but haven't had time to work on it further. |
Ya the two libraries are similar but have a few different goals. I've described LayerCake more as a framework for charting recipes but it's not a charting library exactly. LayerCake is higher-level than Pancake in that it does extent calculation for you, has a D3-like margin convention and has a few chart-minded concepts such as domain padding and bounded ranges. BUT it's much lower level since it doesn't come with any built-in chart types or primitives the way Pancake does. Another goal of LayerCake is to "layer" canvas / html / svg layers on top of one another, which isn't a goal of Pancake. Pancake is pretty great and since LayerCake 3.0, I've incorporated the neat SVG tricks into the ScaledSvg component! |
@mhkeller Long time since our last chat :). I'm finally getting around to porting our React/visx grouped and stacked bar charts to LayerCake, and have a few questions / issues Grouped column exampleI've ported the current Stacked column example as a Grouped column example. I ended up using I did ran into some chicken/egg problems though, as // Needs set after xScale (x0) has range set by chart width
$: $zScale.range([0, $xScale.bandwidth()]) I wish I could could have set it like... <script>
const xScale = scaleBand().paddingInner(0.1);
const zScale = scaleBand().paddingInner(0.05);
</script>
<LayerCake
xScale={xScale}
zScale={zScale}
zRange={() => [0, xScale.bandwidth()]}
> as I saw the overload for xRange/zRange which takes in a function with the width/height, but the scales appear to all be initialized at the same time, so xScale.range() hasn't been set yet. Anyways, it feels a little dirty to set the range within the Some other things I tried... adding the explicit <script>
const xScale = scaleBand().paddingInner(0.1);
const zScale = scaleBand().paddingInner(0.05);
</script>
<LayerCake
xScale={xScale}
xRange={({ width }) => [0, width]}
zScale={zScale}
zRange={() => [0, xScale.bandwidth()]}
> I also tried setting the range directly on <script>
const xScale = scaleBand().paddingInner(0.1);
const zScale = scaleBand().paddingInner(0.05);
</script>
<LayerCake
xScale={xScale}
xRange={({ width }) => xScale.range([0, width]).range()}
zScale={zScale}
zRange={() => [0, xScale.bandwidth()]}
> Anyways, not terrible, but would be nice if this could be handled within LayerCake initialization. Maybe if there was an Thoughts? Issue when swapping chart dataI then moved to support switching between I'm still thinking what data structure I might build to support both use cases (or maybe move the stack / group data building to within I was working to port this Stacked-to-Grouped Bars d3 example with transitions and such but hit this road block. I also plan to create a Grouped Stacked Bar Chart example as well, but was working thorough the 2 items above first before going deeper down the rabbit hole. As always, thanks for all your help. |
@mhkeller I ended up feeling out another approach where I pass in the original data to LayerCake and then handle the specific stack/group data management directly within
I'm still refining / feeling out this approach. I'm not sure how it will work with tooltips and such, but it seems like it might even be cleaner since the data doesn't change (just the visual representation). I'm also considering taking this a step forward and having these layouts be consolidated into a single component so the control of the bars/rects are shared, to allow transitions between the states, etc. Maybe something like... <LayerCake ...>
<Layout stacked let:bars>
{#each bars as bar}
<rect {...bar} />
{/each}
<Layout>
</LayerCake> |
Thanks for doing such a thorough review of what you've been doing. I want to go more deeply into what you've done so far and definitely take a look at that old data issue. One initial thought on the initialization problem is I think it might be tricky since your second scale would need to be initialized after an I really like the idea you have here in your second post of putting some kind of data transform in a component and then exposing that transform via a |
I made more progress towards replicating the Stacked-to-Grouped Bars d3 example by consolidating the I still plan to feel out a combined grouped and stack layout (as I need an additional dimension to visualize in some cases), but all in all, I'm liking how it's coming along. I plan to integrate it into my project with a common Tooltip/Axis/etc and see how it all fits together. I might also experiment creating layout components like I mentioned earlier (which are similar to visx and Victory), but not sure its worth it (and it seems like it will break the tween capabilities from a single keyed iteration, and don't know if something like crossfade would even work with svg to allowed keyed components from different iterations). Anyways, I'll keep posting anymore exploration / progress here if you want (and figure adding a Grouped and/or Grouped/Stacked example to LayerCake would be useful). One of the next areas I plan to explore after this is hierarchy components such as these visx examples I worked on a while back. I know pancake has a nice zoomable treemap example that shouldn't be too hard to port, as a starter. |
Iterated more in the past week. Finally starting to figure out the data structure to make grouped & stacked work at the same time (see 3c+), but still fighting through some issues/regressions on each iteration.
I'll keep tinkering as I get more time, but thought I'd share my progress in case you have any thoughts / improvements. End goal is to support Bar, Stacked Bar, Grouped Bar, and Grouped and Stacked Bar, and variations using different stacked offsets. I'm getting pretty close if you ignore some of the transitions, and still trying to find the right API. I go back and forth with whether the data built for the chart should be done at the start and passed to Bar vs Bar doing the work itself. Mostly with how it will be consumed in other components that read it from the context (Tooltips, etc). I have a lot of shared components I've built at this point that I might look into open sourcing at some point (considering calling it Layer Charts) to provide a high level of abstraction above LayerCake, but can always "break glass" and add your own layers, etc. |
It's looking pretty neat! I think even when I was doing a lot of D3 charts, I didn't dabble much in transition between chart types so you're probably much more expert at this than I am. Having some higher-level components would be really neat and I'd be happy to take a look when you publish them! |
Any ideas why swapping our data and flatData can give odd results? |
`flatData` is used internally to calculate the extents from so if the extents of that dataset differ from data, the scales will adjust.
|
I've been implementing LayerChart as a reusable component library built upon LayerCake, and it has examples for Grouped/Stacked bar charts (and related variants). |
Thanks for the awesome library. I'm just beginning to experiment with Svelte (coming from React) and your library has been very useful to learn how to integrate with d3 (I've contributed to the React vx library in the past and considering porting the Text component to Svelte).
Looking at the guide and example, I see you have a
xScale
,yScale
,zScale
, andrScale
for the scales. For the Stacked Column example,zScale
is used to represent the stack.I was curious, how would this translate to a Grouped Bar Chart or even further with a Grouped Stacked Bar Chart. I know typically the use of
x0/x1
andy0/y1
scales are used. I didn't know if it made since to include at leastx1Scale
andy1Scale
in LayerCake.The text was updated successfully, but these errors were encountered: