Comments (8)
Sure, the same thing in D3 would look like this:
{
const width = 640;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 30;
const marginLeft = 40;
const x = d3.scaleBand()
.domain(d3.utcMonths(
d3.min(aapl, (d) => d3.utcMonth(d.Date)),
d3.max(aapl, (d) => d3.utcMonth.offset(d3.utcMonth(d.Date), 1))))
.range([marginLeft, width - marginRight]);
const y = d3.scaleLinear()
.domain([0, d3.max(aapl, (d) => d.Close)])
.range([height - marginBottom, marginTop]);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto;");
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x)
.tickFormat(d3.utcFormat("%Y"))
.tickValues(d3.utcYears(...d3.extent(x.domain()))))
.call((g) => g.select(".domain").remove());
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y))
.call((g) => g.select(".domain").remove());
svg.append("g")
.selectAll()
.data(d3.rollup(aapl, (D) => d3.median(D, (d) => d.Close), (d) => d3.utcMonth(d.Date)))
.join("rect")
.attr("x", ([key]) => x(key) + 0.5)
.attr("width", x.bandwidth() - 1)
.attr("y", ([, value]) => y(value))
.attr("height", ([, value]) => y(0) - y(value));
return svg.node();
}
https://observablehq.com/d/681d761602f1014d
It’d be a bit harder to get Plot’s multi-line time axis, since d3-axis doesn’t support multi-line text (which is implemented by Plot’s text mark).
Also I think there’s an off-by-one above in some cases: it’s a little tricky to get d3.utcMonths/d3.utcYears etc. to return an inclusive upper bound, since they like to treat the upper bound as exclusive.
from d3-axis.
Here's an example using scaleTime
only, which computes the length of one bar based on time intervals.
https://vizhub.com/curran/14055e4902844acca03ba97d02d1bc72?edit=files&file=index.html#L177
const now = new Date();
const oneMonthWidth =
xScale(d3.timeMonth.ceil(now)) -
xScale(d3.timeMonth.floor(now));
const marks = g
.selectAll('.mark')
.data(data);
marks
.enter()
.append('rect')
.attr('class', 'mark')
.merge(marks)
.attr('x', (d) => xScale(xValue(d)))
.attr('y', (d) => yScale(yValue(d)))
.attr('width', oneMonthWidth)
.attr(
'height',
(d) => innerHeight - yScale(yValue(d))
)
Here's another example that leverages bin
, which has a nice API for getting the min and max values for each bin.
https://vizhub.com/curran/a95f227912474d4a9bbe88a3c6c33ab9?edit=files
Padding is the only "unsolved problem" in this space, but that could be added by adding a constant to X and subtracting double that constant to width.
What I'm saying here is, you can accomplish the thing you describe using the existing D3 API. So I'm not sure the argument to add more API surface area to D3 for this is very strong (but it's a cool idea for sure!).
from d3-axis.
I'm just revisiting this, I built an example here https://ipwright83.github.io/chart-io/?path=/story/xycharts-mixedplots--mixed-stacked-column-plots and haven't yet managed to crack padding.
If you go for the adding a constant to X, would that not pick the ticks out of whack with the data points? I tried an option tweaking the range/domain to add padding which allows you to render data points fully (but was Jacky to get working) and then left my axis line happy at the start/end :(
from d3-axis.
I tend to use the same solution as @curran’s, often with a bit of padding to leave a pixel between the bars.
With Plot you would write (https://observablehq.com/@recifs/shifted-time-bars):
Plot.rectY(
aapl,
Plot.mapX(
(d) => d.map((d) => d3.utcDay.offset(d, -14)), // shift bars left by half a month
Plot.binX(
{ y: "median", title: "min" },
{ title: "Date", x: "Date", y: "Close", interval: "month" }
)
)
).plot()
It would be cool if interval.offset supported fractional offsets, but dealing with time is so difficult that I don't see this happening.
from d3-axis.
I don’t recommend using a time axis if you want to represent time as ordinal (i.e., with bars centered over the ticks); offsetting the position by 14 days won’t work well because months are different lengths (28–31 days, and days are 23–25 hours depending on your time zone).
In Plot, I recommend using a band (ordinal) scale, combining barX and groupX:
Plot.barY(
aapl,
Plot.groupX(
{ y: "median", title: "min" },
{ title: "Date", x: "Date", y: "Close" }
)
).plot({
marginBottom: 80,
x: {
interval: "month",
tickRotate: 90
}
})
Plot is smart enough to know that the ordinal scale represents time thanks to the interval option, but unfortunately it’s still not smart enough to reduce the number of ticks shown automatically, or to apply the new multi-line time axis by default. You can get a better result by setting the ticks explicitly:
Plot.barY(
aapl,
Plot.groupX(
{ y: "median", title: "min" },
{ title: "Date", x: "Date", y: "Close" }
)
).plot({
x: {
interval: "month",
tickFormat: "%Y",
ticks: d3.utcYears(...d3.extent(aapl, (d) => d.Date))
}
})
There should be a way to get the equivalent of the time axis for ordinal time scales… I’ll file an issue over in the Plot repo.
from d3-axis.
Is there any equivalent approach for applying an interval like property in D3? I'm not using Plot, but I might look at the source for some inspiration. A band scale may work, but I'd like to get an axis rendering with the knowledge of time so we don't need every tick
from d3-axis.
https://github.com/d3/d3-time#_interval
from d3-axis.
Thanks @Fil, I'll see if I can apply that to my band scale somehow (and also try some padding on a linear scale) and share my results.
from d3-axis.
Related Issues (20)
- Support external rendering HOT 3
- How to apply pan/zoom to rotated X Axis labels? HOT 1
- Default formatter shows month name instead of Sunday HOT 2
- Date boundary issue for months with 31 days HOT 1
- Suggestion: Add axisTop example HOT 1
- `axis.tickValues` could also return `values`? HOT 3
- Render in vanilla HTML? HOT 2
- Right-align tick text in axisRight() ? HOT 1
- 如何入参是空,那么链式调用将被破坏
- Show scale extrema values in ticks HOT 1
- More configuration options?
- Uncaught TypeError: setting getter-only property "top" when calling axis function HOT 5
- not able to add custom attributes to the axis HOT 1
- Ticks with varying size
- Ticks misalignment HOT 2
- An option to disable the domain line HOT 1
- An option to generate grid lines HOT 3
- Ability to set axis ticks count when using axis `tickFormat` function HOT 6
- d3-axis does not update SVG attributes when switching between axis orientations HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from d3-axis.