Any idea why I can't see two separate rectangles?

I dont… understand this idea.

If I want to add a dot to this graph, I need two pieces of information for my new data point: The Temperature, and the Sales amount.

My data object will contain both of those values.

You’re telling me you want both of your axes to be timescales.

Your data contains exactly 1 time value.

2 != 1.

If I put the graph on the same piece of data, all of the dots will be on a diagonal line. Imagine if that graph was Temperature and Temperature. If my data value for temperature was 10, you’d put the dot at 10,10. If it was 18, you’d put the dot at 18,18…

Hmm. So I will tell you my requirement in simple words and then maybe you can tell me what’s a more appropriate way of handling all of this:

  1. I want horizontal rectangles - the number of lines is determined based on the records I have in that time period.

  2. I need text on each rectangle which is basically the name of the problem I showed in the deidentified data of my last JSFiddle. For example, in the following data, I need to put Hypertensive disorder on the rectangle on the left-hand side.

var problems = [
{
“ID”: “3”,
“Subject”: “Patient”,
“Subject Type”: “patient”,
“Subject Subtype”: “”,
“Subject_ID”: “1544878483”,
“Sub_ID_type”: “DE_ID”,
“Relationship”: “has_finding/condition”,
“Relationship_ID”: “not in athena”,
“Relationship modifier”: “”,
“Rel_modifier_ID”: “”,
“Object”: “Hypertensive disorder”,
“Object Type”: “finding/condition”,
“Object Subtype”: “problem”,
“Object_ID”: “1215744012”,
“Ob_ID_type”: “SNOMED-CT”,
“Timestamp”: “05/12/2020 13:26:00”,
“Parent tuple”: “0”,
“Clarifications”: “Source: problem list FILE”
},

The issue that I faced in above JS Fiddle is explained in my recent post above.

  1. Once above issue is figured out, I will need another way to put circles on the rectangles just like I did it in this JSFiddle of this post above. The location of circle is determined based on the parent tuple relationship as explained in my posts before.

So everything seems to be working till now based on my requirement. Could you tell me what you think is the best way to achieve exactly the same things that I mentioned above? Thanks for your time.

So what I believe you’re trying to tell me is this:

“My two axes are the data values Timestamp and Object. If I want to put a dot on my graph, I need those two pieces of informationto place it.”
Timestamp is… well, a timestamp. So it would be a scaleTime.
Object is a name. Names are a discrete set of values. So that would be a scaleOrdinal.

You want the Timestamp across the top. That makes the scaleTime your X coordinate, so that you move the dot horizontally to be under the right timestamp mark.
You want the Objects down the left side. That makes the scaleOrdinal your Y coordinate, so that you move the dot vertically to be aligned with the correct object name.

Go back and look at the codepen I created. Note how I define the coordinates for my circles (lines 209/210). You can see on line 186 that recordScale is a scaleOrdinal.

1 Like

Thanks very much for pointing me in that direction. So I played around with your codepen and made some changes. Here is the updated one after my changes . The changes I did was changed the timestamp of Rectangle 4 and Rectangle 5 to Timestamp: "5/2/2018 00:00" same as Rectangle 2 and they didn’t mess up just like it is happening in my case even though I see one circle less on the screen now which I can investigate.

I believe that’s what you were trying to explain me from the start that I should use different scale for Object which is a name. So I believe it’s not messing up because of scaleOrdeal function of d3.

So once I put the above scaleOrdeal login in this fiddle, it should not behave as it is behaving now I believe, right?

scaleOrdinal is the correct way to create the graph.

Technically speaking, what’s going wrong in your fiddle is that you’ve told your texts to put themselves at a Y level equal to their timestamp. You’ve got a lot of things that have the same timestamp:

    {
        "ID": "45",
        "Object": "Diabetes Mellitus",
        "Timestamp": "04/06/2021 18:15:00",
    },
    {
        "ID": "46",
        "Object": "Hypertension",
        "Timestamp": "04/06/2021 18:15:00",
    },

so those text boxes appear at the exact same Y coordinate. (If you put the same thing into a function, you’ll get the same thing out!)
You’ve also got several records that are completely outside your timestamp range:

    {
        "ID": "3",
        "Object": "Hypertensive disorder",
        "Timestamp": "05/12/2020 13:26:00",
    },

(I’m trimming out the extra fields so it’s more visible.)

If you have specified a timestamp Domain as:

  var timeScale = d3.scaleTime()
	.domain([new Date("4/1/2021 00:00"), new Date("4/30/2021 00:00")])

5/12/2020 is way outside your timespan domain, so the record disappears from your graph because it’s off-scale low. (It actually is so off scale it generates a large negative coordinate.)

But, these issues can be addressed by using the proper scale.

Since the plan is to use scaleOrdinal, this should not happen there if I’m envisioning it correctly?

I believe in this scenario, I would have to make use of the following:

var timeScale = d3.scaleTime()
.domain([new Date(d3.min(dateArray)), new Date(d3.max(dateArray))])

where, const dateArray = problems.map(d=>new Date(d.Timestamp));

If you want all of the dates in your data represented on the graph, then yes.

You can do it that way; I would use .min and .max to do the lifting for me (I would actually use extent…)

var timeScale = d3.scaleTime()
.domain([d3.min(problems, d => new Date(d.Timestamp)), d3.max(problems, d=> new Date(d.Timestamp))])

or

var timeScale = d3.scaleTime()
.domain(d3.extent(problems, d=> new Date(d.Timestamp))

For the Ordinal, you’ll feed it two arrays; the inputs for the domain (so your Objects), and the outputs for the range (the Y coordinates you want them at). Take a look at the codepen again if you want to see a (slightly complex) example; I would expect questions on that :wink:

Thanks. So I’m currently looking at the code pen and I believe you are referring to the following part as far as feeding Ordinal with two arrays is concerned.

const recordScale = d3.scaleOrdinal()
.domain([…records.map((x) => x.ID)]) // First array goes here
.range([…Array(records.length).keys()].map((y) => y * 24)); // second array goes here

I’ve added some console logs before line 196 to test the values.

I understood the following which is figuring out the domain based on the number of rectangles that needs to be present on the graph.

console.log(“Printing domain”);
console.log(…records.map((x) => x.ID));

The other part of the code which is:

console.log(“Printing Range”);
console.log([…Array(records.length).keys()].map((y) => y * 24));

Can you explain little bit more about this line [...Array(records.length).keys()].map((y) => y * 24) ? I can deduce that you are trying to figure out the space between each rectange on the y coordinate with 24 as the multiple but what is the significance of .keys() here?

Yeah, i figured that part would require some explanation.

So the Ordinal scale needs as many outputs as there are inputs - for example, if i was doing the color chart above, my Domain would be [“Red”,“Blue”,“Green”,“Yellow”,“Pink”]. for each of those values, the scale needs an output in the range. so i might send tye range [0,50,100,150,200]. That way if i ask my scale to put a mark at (“Green”, 20), it would put the mark at (100,someyvalue).

The domain of your ordinal scale will be the unique set of Object; the range is a bit more tricky.

[…Array(somesize).keys()] returns an array of size somesize that is the numbers 0,1,2…somesize-1 ( analogous to the range() function in other languages). I use records.length so i know i have exactly as many entries in my range as my domain (because they were both built off of records). so ive got an array 0,1,2,3… and then map it, mutiplying each value by 24.

Looking back, i could have done it simpler by using map and pulling the index from that. Eh…

1 Like

Hey @m_hutley ,

I plugged in my actual data in the code and it seems to be breaking for some reason.
The only change I’ve done is I’ve stopped using data from printObjectsJson and I’ve defined two new data variables interventions (Line 1804) and labs (line #1). For the final data, I’ve combined interventions and labs and used this variable to pass into the function combinedLabsInterventions everywhere. Here is my updated CodePen:

I was hoping that it would just work with the new big data as it has been working with the small data.

Looks like the d3 version is working to me, other than the y ticks arent confined to a unique set causing some extra-writes, but that’s a minor thing.

You’ll have to be a bit more specific for me what you mean by “breaking”.

I think I fixed the breaking part that I mentioned in my last post so I don’t need to ask about that anymore :slight_smile:

But in order to handle the over-writes, I had to add ID field on Line 5555 .tickValues(records.map((d) => d.ID+" "+d.Subject))

Is there a better way to address this?

Here is my updated CodePen:

Note: I’m making changes only in the new graph and not the original one.

So the question first is: Do you WANT those records separate, or do you want all patients to be on one line?

Technically, here is how it is going to work. For example, let’s consider the following two possibilities:

{
	"ID": "85",
	"Subject": "COPD (chronic obstructive pulmonary disease) / SNOMED CT 475427019 / Confirmed",
	"Subject Type": "finding/condition",
	"Subject Subtype": "problem",
	"Subject_ID": "475427019",
	"Sub_ID_type": "SNOMED-CT",
	"Relationship": "has_intervention",
	"Relationship_ID": "not in athena",
	"Relationship modifier": "",
	"Rel_modifier_ID": "",
	"Object": "albuterol-ipratropium inhal soln 3mg/0.5mg/3mL 3 mL, Inhal Soln, NEB, RT TID, Routine, 4 day(s), 04/06/16 21:00:00, Stop date 04/10/16 20:59:00",
	"Object Type": "intervention",
	"Object Subtype": "medication",
	"Object_ID": "RXNORM!836286",
	"Ob_ID_type": "Rxnorm",
	"Timestamp": "04/06/2021 21:00:00",
	"Parent tuple": "14",
	"Clarifications": ""
}, {
	"ID": "86",
	"Subject": "COPD (chronic obstructive pulmonary disease) / SNOMED CT 475427019 / Confirmed",
	"Subject Type": "finding/condition",
	"Subject Subtype": "problem",
	"Subject_ID": "475427019",
	"Sub_ID_type": "SNOMED-CT",
	"Relationship": "has_intervention",
	"Relationship_ID": "not in athena",
	"Relationship modifier": "discontinued",
	"Rel_modifier_ID": "4132627",
	"Object": "albuterol-ipratropium inhal soln 3mg/0.5mg/3mL 3 mL, Inhal Soln, NEB, RT TID, Routine, 4 day(s), 04/06/16 21:00:00, Stop date 04/10/16 20:59:00",
	"Object Type": "intervention",
	"Object Subtype": "medication",
	"Object_ID": "RXNORM!836286",
	"Ob_ID_type": "Rxnorm",
	"Timestamp": "04/10/2021 20:59:00",
	"Parent tuple": "14",
	"Clarifications": ""
},

As you can see they are almost similar but I would want to display them as one because of the following reason:

  1. In case of ID : 85, the "Relationship modifier": "", is empty. However, in the case of ID:86 the "Relationship modifier": "discontinued", is not empty.
  2. Timestamp for ID:85 is "Timestamp": "04/06/2021 21:00:00", and timestamp for ID:86 is "Relationship modifier": "discontinued",

So while I would like to display both the records as 1 but I would want some way to store both the timestamps in such scenarios. Because even though the record is going to be one, my future enhancement of the code will contain a colorful rectangle with a start date of 04/06/2021 21:00:00 and end data of 04/10/2021 20:59:00.

So even though I want such scenarios to show up as one record, I would like to kee above thing in my mind while displaying them.

so this is where you start thinking about how you represent things on your visualization.

If the Y scale is Object, and the X scale is Timestamp, how are these objects different from one another? The timestamp is very slightly different, so you can separate these two data points by that.

What about relationship modifier?
Well, you’ve got a few options on a scatter plot like this; if the values for relationship modifier are limited in number, you might consider for example another Ordinal scale, and fill the circles a different color based on their relationship modifier. You might make them different shapes, or different sizes. These are all options.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.