-
Notifications
You must be signed in to change notification settings - Fork 13.8k
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
Time Series Annotation Layers #3521
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few minor things, looks great!
class SelectAsyncControl extends React.PureComponent { | ||
constructor(props) { | ||
super(props); | ||
this.state = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many of the other controls to not maintain internal state and rely solely on the value
prop and onChange
to act as a controlled component. There's nothing bad with maintaining the state here but it adds a bid of complexity that is not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
.attr('height', 10) | ||
.attr('patternTransform', 'rotate(45 50 50)') | ||
.append('line') | ||
.attr('stroke', '#00A699') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked like this color is @brand-primary
, any way we can use a CSS class instead of hard-coding the color here?
.attr('fill', 'url(#diagonal)') | ||
.attr('fill-opacity', 0.1) | ||
.attr('stroke-width', 1) | ||
.attr('stroke', '#00A699') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, let's not hard code the color
@@ -0,0 +1,22 @@ | |||
"""empty message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised to see 2 different merge migrations. Legit or mistake?
superset/models/core.py
Outdated
@@ -25,7 +25,7 @@ | |||
|
|||
from sqlalchemy import ( | |||
Column, Integer, String, ForeignKey, Text, Boolean, | |||
DateTime, Date, Table, | |||
DateTime, Date, Table, Index, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Index
is unused, I think I left that dirt behind in my commit...
superset/viz.py
Outdated
@@ -111,6 +112,7 @@ def get_extra_filters(self): | |||
|
|||
def query_obj(self): | |||
"""Building a query object""" | |||
print("running query_obj============================") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove this line
.attr('class', 'd3-tip') | ||
.direction('n') | ||
.offset([-5, 0]) | ||
.html(d => (d && d.layer ? d.layer : '')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should surface more here, the layer name, the short and the long description.
}) | ||
.attr('height', hh) | ||
.attr('fill', 'url(#diagonal)') | ||
.attr('fill-opacity', 0.1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: I think the annotations look good on the gif, we can talk to Eli & Chris to fine tune their look if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class could be called stroke-primary
60b9cbd
to
13ace05
Compare
Coverage increased (+0.06%) to 69.615% when pulling 13ace05775b1313e150a49092a867fab06bd994b on graceguo-supercat:annotations into 3949d39 on apache:master. |
1 similar comment
Coverage increased (+0.06%) to 69.615% when pulling 13ace05775b1313e150a49092a867fab06bd994b on graceguo-supercat:annotations into 3949d39 on apache:master. |
Coverage increased (+0.06%) to 69.615% when pulling 13ace05775b1313e150a49092a867fab06bd994b on graceguo-supercat:annotations into 3949d39 on apache:master. |
- add annotation input sanity check before add and before update. - make SelectAsyncControl component statelesis, and generic - add annotation description in d3 tool tip - use less variable to replace hard-coded color
13ace05
to
1313151
Compare
@@ -57,6 +57,7 @@ def __init__(self, datasource, form_data): | |||
'token', 'token_' + uuid.uuid4().hex[:8]) | |||
self.metrics = self.form_data.get('metrics') or [] | |||
self.groupby = self.form_data.get('groupby') or [] | |||
self.annotation_layers = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think annotations should be part the viz object. For most viz types that I can think of annotations don't really make sense. If you make annotations accessible from a json endpoint they can be loaded client side. This would also make the responsiveness better, annotations could be loaded async independently of the data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we decided to package the annotations from the backend along with the data payload. The visualizations' render method can then assume that all of the data + annotations + context is present when rendering. Note that the annotation query is fully indexed and should take milliseconds assuming a small-ish number of annotations for the time range.
I feel like if we wanted to go async on the annotations, we'd need to change the visualization's API to define 2 different methods and somehow guarantee to call the annotation one second. It makes things much more complicated on that side of things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
34ec8b3#diff-a85def8afdc240ac598637a26a7cdbbc I can probably clean this up a bit more, but this makes all http requests in parallel.
from .base import SupersetModelView, DeleteMixin | ||
|
||
|
||
class AnnotationModelView(SupersetModelView, DeleteMixin): # noqa |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are annotations written to that table? If you cannot write them from within superset, why are you not thinking of them as just another datasource?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feature ships with the FAB CRUD UI that allows users to manually input/manage layers. FAB also exposes a CRUD REST API to maintain those programmatically, though I'm thinking at Airbnb most likely people will write Airflow jobs talking to our MySQL instance to load annotations dynamically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that this table should be part of the Superset DB then. The way Superset is currently designed is that it is agnostic (as long as there is a Druid/SQL connector) to where the data is stored. We have a clean separation of meta data (slice definition, configuration, users, ...) and the data that superset is operating on.
This table inverses this fundamentally and now we have to store presentation data directly inside of the superset db. Currently no time series data is stored inside of the superset database. I'm also worried that this will cause scalability issues. Now my superset meta database is going to have very different performance requirements with regard to querying time series.
If this table was only used for manually created data from a user interface you could make the argument that we are talking about a very limited amount of data which originated in superset and therefore should be stored there. But this seems not to be the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's at the frontier of data/metadata, though to me annotations are closer to metadata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I agree that it would be sweet to support external data for annotations (as in your PR), let's do both. I have some thoughts on that that I'll put on your PR. The TLDR is I think we should create a new time_annotations
viz_type to enforce a certain set of guaranties, as opposed to a convention on top of the table
viz_type.
'annotation', | ||
sa.Column('created_on', sa.DateTime(), nullable=True), | ||
sa.Column('changed_on', sa.DateTime(), nullable=True), | ||
sa.Column('id', sa.Integer(), nullable=False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bigint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hoping we never go above 2,147,483,647 annotations, saving some bytes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have automated processes writing to this table (airflow) we should change this to BIGINT. The disk space you save is only relevant in cases when you have a lot of rows, which is also when you want to have BIGINTs as your IDs.
I just created a couple youtube videos of the functionality of my changeset, #3518 |
@fabianmenges going to comment on your PR to think holistically about annotations. We spoke about your approach internally and think it's very complementary and would love to integrate all this. |
@fabianmenges we may need to talk to sync up about annotations, we all really like the work that you've done and do want to support the stuff you added:
Throw in:
On top of this PR, which I would describe as:
All this should be composable. I'd like to break down 1-2-3 from 4 potentially, though if we can agree on the vision we could make your current PR evolve into 1-2-4 combo. That's a pretty massive feature set though. |
Lets move this to the dev mailing list... |
Go ahead and merge this in, I can integrate the UIs in my merge request. Lets have the design discussion in the mailing list. |
* Adding annotations to backend * Auto fetching Annotations on the backend * Closing the loop * Adding missing files * annotation layers UI for apache#3502 * a few fixes per code review. - add annotation input sanity check before add and before update. - make SelectAsyncControl component statelesis, and generic - add annotation description in d3 tool tip - use less variable to replace hard-coded color
fixes #3502