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

Assuming you actually want your X coordinates restrained to 0-210, and you want the rectangles to be on the same spacing as the circles, then yeah. Without knowing exactly what you want the graph to look like, I can’t definitively say “yes thats right” or not.

So i’ll give you what I was thinking about the dates and your scale extent. You may or may not want to use it, but its probably a good thing to learn about anyway.

Rather than giving concrete dates, we may want to be responsive to the data we receive. The data in your sample, for example, ranges from 5/1/2018 to 5/5/2018. Previously, you’d said your range was until 5/8/2018.

If we wanted to span from the beginning to the end, without knowing what the values are ahead of time, we need to do some digging on our data - the domain, after all, needs a minimum and maximum value.

d3 recognized that this would be a common task, and has implemented methods to extract that information - d3.min(), d3.max(), and d3.extent.

As you might expect, min() finds the smallest value in the data; max finds the largest. Extent(), however, finds both - the minimum, and the maximum, and returns them as a 2-item array.

We wouldn’t think we can feed it the whole object - it doesnt know how to compare

  { "ID":"7",
		"s1": "Rectangle 4",
    "Parent tuple": "2",
    "Relationship": "has_rectangle",
    "Timestamp": "5/4/2018 00:00",
	}

to

   { "ID":"8",
		"s1": "Rectangle 5",
    "Parent tuple": "1",
    "Relationship": "has_rectangle",
    "Timestamp": "5/5/2018 00:00",
	}

(maybe we want to compare by ID, or Parent, or s1…?)
We could do some fancy work with map again… but d3 has us covered already. extent (and min and max, for that matter!) can take a second parameter; a function that defines how to access the data object, so d3 knows what to use for a comparison.

In our case, we would want the Timestamp. Let’s for the moment assume we have converted the strings into Dates already.

extent can find our max and min values in a single command:
d3.extent(circles, d => d.Timestamp)

Which would return the min and max values in an array:
d3.extent(circles, d => d.Timestamp) << [Tue May 01 2018 00:00:00 GMT-0400 (Eastern Daylight Time), Fri May 04 2018 00:00:00 GMT-0400 (Eastern Daylight Time)]

Which, as it turns out, is exactly what .domain() is expecting… so…

  var timeScale = d3.scaleTime()
	.domain([new Date("5/1/2018 00:00"), new Date("5/5/2018 00:00")])
 	.range([0, 220]); 

=>

  var timeScale = d3.scaleTime()
	.domain(d3.extent(circle, d => d.Timestamp))
 	.range([0, 220]); 

And suddenly your scale will adjust itself to fit any timespan data you happen to ingest…(Note: Because this is only based off of the circles, you will actually make your range until 5/4, meaning that the last rectangle disappears; so you might want to do the timescale on your whole data set, rather than the filtered ones)