Skip to content
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

[WIP] Trace picker updates #311

Merged
merged 14 commits into from
Mar 3, 2018
Merged

[WIP] Trace picker updates #311

merged 14 commits into from
Mar 3, 2018

Conversation

aulneau
Copy link
Contributor

@aulneau aulneau commented Feb 7, 2018

Okay!

So this is not quite ready yet. I've built out the views and I built out a little modal provider that we can use with other modals if we want to keep it.

chart-editor

General structure of the updates:

I've added two new props to PlotlyEditor:
advancedTraceTypeSelector which enables everything, and traceSelectorConfig which passes our default configs to the enhanced trace type selector. The default config values are coming from some constants I ported over from streambed which you can see here. Let me know if this data structure should change.

I have created a ModalProvider.js which passes two functions through context to anywhere in the application: openModal(component) and closeModal(). We call openModal and pass it a component -> see here.

I have also created a Modal.js component that we can pass params to. Currently it accepts a title param for the header, and then we can pass it content via children wrapped in <ModalContent>...</ModalContent> I might just bake this in rather than using a sep wrapper component for this. The Modal.js takes care of animating in/out.

Where I need help // cc @VeraZab @nicolaskruchten
I am not exactly sure the best way to hook up the TraceTypeSelector.js to be able to affect the larger application state (change chart types, only allow X type charts if Y type chart is already selected (see here), etc. Currently I am passing the same props that we pass to the drop down to the TraceTypeSelector.js, but I will need some guidance moving forward.

Things I still need to do:

  • Hook up the enhanced picker to actually change the trace type
  • Convert the new chart type images to react svg components (and add the last 2 from @fabric-8)
  • Provide a way for people to pass in custom images along with their custom data
  • Possible default image/icon for a chart type that is passed but does not have a plotly image / provided image
  • Allow item actions to be customizable

Will resolve: #238

@VeraZab
Copy link
Contributor

VeraZab commented Feb 7, 2018

Convert the new chart type images to react svg components

do you mean by this: put these icons into the plotly-icons repo?

@aulneau
Copy link
Contributor Author

aulneau commented Feb 7, 2018

@VeraZab possibly -- these svgs are a lot more complex (various strokes, different colors) -- but it might make sense to add them there. I'll have to either manually make them into components or adjust our generating scripts for them.

@VeraZab
Copy link
Contributor

VeraZab commented Feb 7, 2018

To make the Modal change the plot, you have the updateContainer prop, you can pass it the value of the chart that the user clicks on. So for ex, for a timeseries chart, we have to make sure the timeseries value is passed on. It's a custom type. Careful with the custom types. We have that function plotlyTraceToCustomTrace to make those conversions, it takes container as an argument (gd.data).

@VeraZab
Copy link
Contributor

VeraZab commented Feb 7, 2018

but it might make sense to add them there.

yup, I think it does make sense to add them there, that repos purpose is really to take care of all our icons

@nicolaskruchten
Copy link
Contributor

A few comments:

  1. Looks great!
  2. regarding the 2d/3d chart exclusion, basically in this component there needs to be some check of what's currently in the figure, and then some decision about which chart types to grey out. We can implement this after the basic version is done in a separate PR, but I don't see this as "affects the larger application state" so much as "conditionally renders based on state" if you see what I mean...
  3. (Vera beat me to it)

<StyleColorbarsPanel group={_('Style')} name={_('Color Bars')} />
</PanelMenuWrapper>
<Fragment>
<PanelMenuWrapper>
Copy link
Contributor

Choose a reason for hiding this comment

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

is Fragment needed there?
If I understand correctly, Fragment's used to group elements in place of wrapping them in a div, but I don't see why it'd be useful here..?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops that's left over from when I was exploring ways of adding the modal :)

import {bem} from './lib';
import {noShame, maybeClearAxisTypes} from './shame';
import {EDITOR_ACTIONS} from './lib/constants';
import isNumeric from 'fast-isnumeric';
import nestedProperty from 'plotly.js/src/lib/nested_property';
import {CATEGORY_LAYOUT, TRACE_TYPES} from 'lib/constants';
import {ModalProvider} from 'components/containers';

Copy link
Contributor

Choose a reason for hiding this comment

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

we have a modal system in webapp, and I think that with a modal system being present now in the editor, this just means that both modal systems will have to coexist. Because the biggest thing in webapp with Modals was that we wanted to have Modal action chains.

One modal appears, then based on user's action, another one displays. But I think it's ok not to worry about it too much here. I think that what will most likely happen is that there's 2 modal systems that will exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I was curious about that, I figured that in this version of the editor we didn't need chained modals, but I think we could merge it into one when the time comes :)

this.context.openModal(<TraceTypeSelector {...props} />)
}
>
<UnconnectedDropdown {...props} />
Copy link
Contributor

Choose a reason for hiding this comment

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

Just from a UI and visual standpoint, maybe it should look more like a button here, instead of an UnconnectedDropdown?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool -- I will build out a button similar to what is in the workspace currently :)

@nicolaskruchten
Copy link
Contributor

nicolaskruchten commented Feb 7, 2018

re how to wire things in to the bigger context, take a look at how the other widget/field pairs work.

basically your TraceTypeSelector is an unconnected widget, and the TraceSelector is a field which connects it. So the field will pass you a prop of your choice bound to its props.updatePlot which you need to call whenever the user makes a choice.

Edit: right now TraceSelector cheats because it grabs UnconnectedDropdown from fields instead of widgets, so a better pair to look at is Numeric/NumericInput :)

aria-label="View tutorials on this chart type."
data-microtip-position={`top${position}`}
role="tooltip"
>
Copy link
Contributor

Choose a reason for hiding this comment

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

ok, you'd add the tutorial link later? just a reminder :) it should be an a tag?
and actually, I think this text _('View tutorials on this chart type') has to be localized.

There's a few places in here where text needs to be localized : )

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I think I am going to abstract these out anyway to they are a part of the config that a user can pass through... enable them, change them, etc

<div
className="trace-item__actions__item"
aria-label="See a basic example."
data-microtip-position={`bottom${position}`}
Copy link
Contributor

Choose a reason for hiding this comment

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

localized

STATISTICS: 'STATISTICS',
MAPS: 'MAPS',
};

Copy link
Contributor

Choose a reason for hiding this comment

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

Could these structures be simpler, like:

export const CHART_CLASS = {
 GEOGRAPHIC: ['atlas', 'choropleth', 'scattermapbox']
}

CHART_CATEGORY is needed for the picker and CHART_CLASS for compatibility and disabling and enabling different plots. So I see why both are needed. But I don't see why we should repeat that whole object that lists all chart types..

};

export const CATEGORY_LAYOUT = [
{category: CHART_CATEGORY.BUSINESS, label: 'Business'},
Copy link
Contributor

Choose a reason for hiding this comment

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

These Category layouts need to be localized


export const TRACE_TYPES = {
scatter: {
meta: {
Copy link
Contributor

Choose a reason for hiding this comment

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

this is kind of repeating, with more detail, what we have here:
https://github.com/plotly/react-plotly.js-editor/blob/master/src/components/fields/TraceSelector.js#L21

I don't see it's necessity

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Much of these consts were pulled from streambed I was not sure how much of it should stay / how much of it should go.

What do you think about moving https://github.com/plotly/react-plotly.js-editor/blob/master/src/components/fields/TraceSelector.js#L21 into the constants.js file?

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't have to use what streambed has : ) we just need the logic (basically which chart types go into which categories). Plus our new requirement now is that users can make that configurable. So the best data structure is the one that's simplest to use in an API.

About https://github.com/plotly/react-plotly.js-editor/blob/master/src/components/fields/TraceSelector.js#L21 I think they're here because trace names need localization, and that localize function must wrap a component to make the localize prop available to it.

We should probably be making localize available at the very top level of our app, localizing component per component is a bit rough and unecesary..

I don't mind moving all trace types to the constants folder though..

Copy link
Contributor

Choose a reason for hiding this comment

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

there should definitely be one canonical mapping from trace type to localized trace name, so that if I have access to "scatter" and _ I should be able to get at the localized name. Makes sense to move that into constants and pack in the default categorization as well IMO.

@@ -0,0 +1,99 @@
.modal {
$c: &;
position: fixed;
Copy link
Contributor

Choose a reason for hiding this comment

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

is this a forgotten variable?

@VeraZab
Copy link
Contributor

VeraZab commented Feb 9, 2018

hey @aulneau!
we've discussed this a little bit here: #260 (comment)

And finally decided not to put these as separate trace types into the chart picker: 'error bars', 'animations', 'timeseries'. Would you remove them from the picker, please.

@aulneau
Copy link
Contributor Author

aulneau commented Feb 9, 2018

Okay I've started going through and creating lists based off of the icons that Fab has made, and the list I pulled from streambed, and the list contained here in this editor and this is what I've got so far:

Trace types with category and icon -> here

Trace types with icon but no category -> here

Trace types with no icons and no category -> here

Also @VeraZab and @nicolaskruchten do we want to couple the category type in with the trace type, eg:

A

    {
        value: 'scatter',
        label: _('Scatter'),
        category:CHART_CATEGORY.BUSINESS,
    },

or do we want to keep trace types clean and do something like:

B

    {
        value: 'scatter',
        label: _('Scatter'),
    },
---
const categories = [
  {
    value: 'statistics',
    label: _('Statistics'),
    traces: ['scatter', 'line', ...more],
  },
  ...
];

I am leaning more towards A.

@nicolaskruchten
Copy link
Contributor

I like A, it's DRYer

@aulneau
Copy link
Contributor Author

aulneau commented Feb 9, 2018

Okay -- I have added all the trace types that have icons into categories.

cc @VeraZab @nicolaskruchten @jackparmer for any suggestions on moving trace types to a more appropriate category:

screen shot 2018-02-09 at 10 46 32 am

@nicolaskruchten
Copy link
Contributor

Hmmm. How attached are we to our existing categorization scheme, @jackparmer ? It seems a bit limiting at this point if we're adding all the other trace types...

Maybe we want to use a more function-oriented approach like this? https://datavizcatalogue.com/search.html or https://visual.ly/community/infographic/how/graphic-continuum

There are bunch of other organization types here https://github.com/widged/data-for-good/wiki/Visualisation-::-Choosing-a-chart

@jackparmer
Copy link
Contributor

jackparmer commented Feb 9, 2018

Hmmm. How attached are we to our existing categorization scheme

Not attached to it at all. I'm sure y'all can come up with something much better.

Edit: I think the "functional" categorization is too high brow though. Is there a 7th categorization to take the weight off of the "Science" column? Maybe a "Heatmaps" column where we put heatmap, countour, 2d histogram, and 2d histogram contour.

There's also a bit of shuffling to do in the current screenshot: carpet and sankey should be under "Science". parcoords I think should be under "Stats"

@nicolaskruchten
Copy link
Contributor

Here's a slightly different typology which includes all 3 carpet types and might fit into a 4-row/8-column grid.

  • Simple (8, first row)
    • Scatter
    • Bar
    • Line
    • Area
    • Heatmap
    • Contour
    • Table
    • Pie
  • 3D (5, second row)
    • 3D scatter
    • 3D line
    • 3D surface
    • 3D mesh
    • Pointcloud
  • Maps (3, second row)
    • Choropleth
    • Satellite
    • Atlas
  • Distributions (5, third row)
    • box
    • violin
    • histogram
    • 2d histogram
    • 2d contour histogram
  • Finance (2, fourth row)
    • OHLC
    • Candlestick
  • Specialized (7, fourth row)
    • Ternary
    • Polar
    • Parallel Coordinates
    • Sankey
    • Carpet
    • Scatter Carpet
    • Carpet Contour

@jackparmer
Copy link
Contributor

I like it! Only thing is pointcloud isn't 3d. I think we should have a 7th column called "2d WebGL" that has scattergl, pointcloud, scatterpolargl, and heatmapgl. This will be good for us - it's too hard to play around with the WebGL trace types currently.

@nicolaskruchten
Copy link
Contributor

I was thinking that the GL types would be like a checkbox or something rather than a first-class citizen in this trace-picker. The user looking at this might not want to make the "underlying technology" choice at this point...?

What's pointcloud if not 3-d?

@jackparmer
Copy link
Contributor

jackparmer commented Feb 9, 2018

+1 Checkbox/switch sounds great to me. Maybe on the top-right here? One side of the switch says D3/SVG and the other side says WebGL?

image

What's pointcloud if not 3-d?

This magical trace type that @monfera wrote for uber refresh rates with lots of 2d scatter data:

https://codepen.io/monfera/pen/BLjJVZ
https://plot.ly/javascript/pointcloud/

If users want to plot a stupid # of x-y points interactively, we point them to pointcloud

@nicolaskruchten
Copy link
Contributor

One downside to the SVG vs WebGL thing at the trace-picker level is that then 3D would need to go under WebGL, right?

@jackparmer
Copy link
Contributor

I would label it "2d WebGL" and keep 3d charts under both views

@nicolaskruchten
Copy link
Contributor

OK so my initial thinking about the checkbox was outside of this modal. If we want to have the GL versions on this modal, I would go with a separate section called "WebGL accelerated" or something with those trace types in there.

@jackparmer
Copy link
Contributor

👍 "WebGL accelerated" column. I don't have a strong preference about the WebGL display as long as they are easy to access like the other trace types.

}
if (
plotlyTraceToCustomTrace(context.container) === 'timeseries' &&
(!context.layout.xaxis ||
Copy link
Contributor

Choose a reason for hiding this comment

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

oh.. we removed this code.. maybe time for a little rebase?..

href: `#`,
icon: <GraphIcon />,
},
];
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, it's ok, we can add these in another pr : )

function computeTraceOptionsFromSchema(schema, _, context) {
// Filter out Polar "area" type as it is fairly broken and we want to present
// scatter with fill as an "area" chart type for convenience.
const traceTypes = Object.keys(schema.traces).filter(
Copy link
Contributor

Choose a reason for hiding this comment

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

so, when is this code activated now?
When advancedTraceTypeSelector is not provided as a prop to the PlotlyEditor Component?
I think the user should still be able to configure the plot types even if they don't choose the advancedTraceTypeSelector.

So this should be adjusted and only read from schema if a trace config was not given.
And these should be the excluded types for now: 'area', 'violin', 'pointcloud', 'parcoords', 'sankey', 'carpet', 'scattercarpet', 'contourcarpet', 'scatterpolar'

@@ -25,6 +25,8 @@ export function traceTypeToPlotlyInitFigure(traceType) {
return {type: 'scatter', mode: 'markers', fill: 'none'};
case 'area':
return {type: 'scatter', fill: 'tozeroy'};
case 'cartesianArea':
return {type: 'scatter', fill: 'tozeroy'};
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will remove :) it was held over from when I ported some stuff over from streambed

label: _('Heatmap GL'),
category: chartCategory(_).WEB_GL,
},
];
Copy link
Contributor

Choose a reason for hiding this comment

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

great : ) thanks!!

Copy link
Contributor

@VeraZab VeraZab left a comment

Choose a reason for hiding this comment

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

ok, well, as this was almost ready for a rereview, except for new icons, I think it needs a few readjustments as per comments, but looks great, and almost ready!! 🎉 thanks @aulneau !

@VeraZab
Copy link
Contributor

VeraZab commented Feb 20, 2018

I think I'd vote here to make these adjustments, and merge this pr in. We have all the icons for the currently integrated traces in the editor. We can make smaller prs to integrate the rest, and make layout improvements as we go.

@@ -83,6 +83,7 @@ class App extends Component {
dataSources={dataSources}
dataSourceOptions={dataSourceOptions}
plotly={plotly}
advancedTraceTypeSelector
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this flag? this is basically going to be the default config right?

Copy link
Contributor

Choose a reason for hiding this comment

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

ignore this comment, i have no objection here :)

@VeraZab
Copy link
Contributor

VeraZab commented Feb 28, 2018

@aulneau checked out your branch and played around with it, looks good! let's merge!
and then when all icons are in plotly-icons we can make those changes in another pr. thanks!! 🎉

@VeraZab VeraZab force-pushed the trace-picker-updates branch 2 times, most recently from 064d0a9 to dddd62b Compare March 3, 2018 02:51
@VeraZab
Copy link
Contributor

VeraZab commented Mar 3, 2018

ok, I think I resolved all rebase issues here, going to merge and if anything was missed then we'll see pretty soon :)

@VeraZab VeraZab merged commit e47aae5 into master Mar 3, 2018
@VeraZab VeraZab deleted the trace-picker-updates branch March 3, 2018 03:15
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.

Enhance chart picker dropdown
5 participants