Open techniq opened 11 months ago
Continuation of some of the discussion in issue #54. (cc: @mattlangeman)
See also #21, particularly:
FYI: I've started looking into this issue on a branch here: https://github.com/mattlangeman/layerchart/tree/temp-bar-timescales
The main issue I've run into so far is dealing with the last bar going off the edge of the chart. I was able to solve this by adding an extra day to the xDomain, but it doesn't seem ideal to need this all of the time.
Maybe it makes sense to add this a default in Chart.svelte if it is a barchart and using timeScale.
I also need a way to detect that it is a barchart using timeScale in order to shift the ticks in Axis.svelte
I think we need some type of interval setting or detection to determine if we are dealing with days/months/quarters/years, etc.
Note: I've only focused on the Columns/vertical bars for now.
Overview to todos:
I'm also wanting to add in support for multi-level axis for time scale data. I have some preliminary code, but definitely still needs work on abstracting and refining.
Some quick thoughts...
A way to detect if it's a barchart with timeScale (or some other way to know we need to shift ticks and adjust domain)
Currently checking for band scales (barchart) using isScaleBand().
For timeScale(), I don't see anything directly on the scale to indicate it...
but maybe if the .domain()
are Date
instances AND it's a continuous scale, that might work.
Basically need to change if x is band and y is time, or vice versa.
An interview setting or detection for day/month/quarter/year/???
You might take a look at getDuration in Svelte UX, along with getMinorTicks
/ getMajorTicks
in ticks. I've been meaning to incorporate this for smarter date ticks as well. Lastly, Svelte UX has PeriodType.Day
, PeriodType.Month
, etc which are used for explicit date formatting. We've done a lot of work in the upcoming Svelte UX release that improves Intl support as well. I think we can improve the docs even more, but take a look at format.
A way to override domain to extend it so the last bar remains on the chart
the same would be helpful with using line with a step curve. I've manually added an extra data point in this situation as well, so having a util function to wrap <Chart data={duplicateLast(data)} />
or <Chart {data} duplicateLast />
(just thinking out loud, and not set on name).
// Add extra data point to fix last day/month
$: chartData = [
...data,
{
...data[data.length - 1],
date: endOfMonthFunc(data[data.length - 1]?.date),
},
];
I'm also wanting to add in support for multi-level axis for time scale data. I have some preliminary code, but definitely still needs work on abstracting and refining.
I'm also wanting this. Observable Plot does a nice job of this (like Datawrapper)...
and zoomable-timeline has been something I've wanted to dig in more. Also semi-related - AutoChart
@mattlangeman bit of a hack/workaround, but today I wanted to add a daily volume chart to my Github Analysis site (bar chart under the area chart), and accomplished this by passing all the days within the extents using d3-time
's .range()
https://github.com/techniq/github-analysis/blob/main/src/routes/stars/%2Blayout.svelte#L51-L52
This isn't the easiest example to see with a wide range. If I only show the last 50 points, you can see the band/scale better...
and using xNice
will better align the area and bar charts (band ticks being in the middle of the day)
I still want to support scaleTime
with Bars
, and will continue to think about how to enable that, but this does seem to work by still leveraging scaleBand()
One thought I had to detect using a Bars
was possibly passing <Chart xInterval={timeDay)>
(or yInterval
) similar to plot
One option (and maybe the best) is to pre-bin the data using d3's bin() along with either thresholdTime
from LayerChart (for nicer date boundaries), or bin by d3-time interval (days, weeks, etc).
import { bin } from 'd3-array';
import { thresholdTime } from 'layerchart';
const = 10;
const binByTime = bin().thresholds(thresholdTime(count));
const data = binByTime(sourceData);
import { bin } from 'd3-array';
import { timeDays, timeWeeks, timeMonths, ... } from 'd3-time';
const binByTime = bin().thresholds((data, min, max) => timeWeeks(min, max));
const data = binByTime(sourceData);
I've added some Histogram examples for these 2 approaches.
Instead of using
scaleBand
for a lot of our time-based Bar examples, Bar / Bars should be updated to support linear scales such asscaleLinear
andscaleTime
.This should probably be handled within createDimensionGetter(), and likely be similar (if not exactly) to how Highlight does this.
If the same, we could probably consolidate the usage into common utils.