Skip to content

Add a "line" marker option #1868

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

Closed
wants to merge 4 commits into from
Closed

Conversation

guizmaii
Copy link

@guizmaii guizmaii commented Sep 21, 2023

Useful to render "error" in bars

Here is a (zoomed) example:
Screenshot 2023-09-21 at 4 58 40 pm

It's my first PR here and I'm, in general, not used to making PRs on JS/TS projects, so please let me know if anything is missing (tests, etc.), I'll add anything missing 🙂

Also, I'm a super newbie with SVG. To make this work, I just copy/pasted the arrow marker and changed it until it was rendering what I wanted. I'm absolutely not sure of what I'm doing here 😅

src/marker.js Outdated
.attr("stroke-width", 1.5)
.attr("stroke-linecap", "square")
.attr("stroke-linejoin", "square")
.call((marker) => marker.append("line").attr("x1", "0").attr("x2", "0").attr("y1", "-2").attr("y2", "2"))
Copy link
Author

Choose a reason for hiding this comment

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

y1 & y2 values at -2 and 2 are arbitrary. That was rendering well in my charts.
Let me know if you want to change them 🙂

Copy link
Author

Choose a reason for hiding this comment

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

Made some change to make it configurable

@Fil
Copy link
Contributor

Fil commented Sep 22, 2023

Thanks for sharing! Instead of changing Plot's source code, you can pass a function as a marker. That function can be configurable, to indicate the length of the tick. You might also want to use orient=auto so that it rotates with the curve; see for example:
https://observablehq.com/@recifs/plot-custom-markers

@guizmaii
Copy link
Author

Hi @Fil

Thanks for the feedback and the link 🙂

Instead of changing Plot's source code, you can pass a function as a marker

That's what I did, see:
Screenshot 2023-09-23 at 3 20 49 pm
Screenshot 2023-09-23 at 3 21 01 pm

My issue was that I didn't know how to make a marker so I had to copy/paste some code from Plot internals (the create function in the screenshot).
Your link shows how to do it without having to copy Plot internals, thanks 🙂
Maybe this example should be added to the documentation, WDYT?

Finally, I still think it could be a good thing for Plot to have this additional default marker. That's why I submitted this PR.
It's not unusual to want to show "error bars", it's an option in a lot of charting libs, and this marker allows you to make these "error bars" look nice, I think.
WDYT?

@Fil
Copy link
Contributor

Fil commented Sep 23, 2023

It's still not configurable, though I don't know exactly how we'd make it simple to configure. One thing that I would like to change also is the name, because marker "line" does not really evoke this marker that is a small tick across the line (in other words perpendicular to the curve).

@guizmaii
Copy link
Author

guizmaii commented Sep 23, 2023

It's still not configurable, though I don't know exactly how we'd make it simple to configure

I think the easiest way would be to export the function so that people can use it directly:

markerStart: (color, context) => markerLine(4)(color, context)

One thing that I would like to change also is the name,

Agreed. The current name is not ideal. Open to suggestions 🙂

@mbostock
Copy link
Member

I appreciate the suggestion, but I don’t think we would take this approach to implement error bars; the upper and lower bounds of the error bar should be specified in abstract coordinates rather than in pixels (and maybe asymmetric). Perhaps instead we should take the existing rule mark and extend it to support little bars at the end.

Here is an example using rule as it exists today:

untitled (92)

Plot.plot({
  marks: [
    Plot.barX(alphabet, {x: "frequency", y: "letter", sort: {y: "-x"}, fill: "steelblue"}),
    Plot.ruleY(alphabet, {x1: (d) => d.frequency * 0.9, x2: (d) => d.frequency * 1.1, y: "letter"}),
    Plot.ruleX([0])
  ]
})

And here is an example using the tick mark to draw the ends of the error bars:
untitled (93)

Plot.plot({
  marks: [
    Plot.barX(alphabet, {x: "frequency", y: "letter", sort: {y: "-x"}, fill: "steelblue"}),
    Plot.ruleY(alphabet, {x1: (d) => d.frequency * 0.9, x2: (d) => d.frequency * 1.1, y: "letter"}),
    Plot.tickX(alphabet, {x: (d) => d.frequency * 0.9, inset: 6, y: "letter"}),
    Plot.tickX(alphabet, {x: (d) => d.frequency * 1.1, inset: 6, y: "letter"}),
    Plot.ruleX([0])
  ]
})

Notebook: https://observablehq.com/d/a2cad4b219d69125

@mbostock mbostock closed this Sep 24, 2023
@mbostock mbostock mentioned this pull request Sep 24, 2023
@guizmaii guizmaii deleted the line_marker branch September 27, 2023 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants