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

Support for multiple types in one chart #53

Closed
jbaron opened this issue Apr 3, 2022 · 4 comments
Closed

Support for multiple types in one chart #53

jbaron opened this issue Apr 3, 2022 · 4 comments

Comments

@jbaron
Copy link

jbaron commented Apr 3, 2022

Great wrapper around ECharts, also looks easy to use.

One question I have though, is it possible to mix different series types? For example if I create a CandleStick chart, I can not add series of Line type (or at least not obvious to me how to do this). It seems a chart is limited to a single type (but multiple series of that type can be added), is this correct?

@icepear-jzx
Copy link
Member

Thanks for using ECharts Java and your issue. Yes, the Chart APIs (Line, Candlestick, etc.) don't support multiple series types. This is for simplicity (many users may be unwilling to read Apache ECharts Docs). However, you can construct an Option by yourself, and it's pretty simple.

For the example from Apache ECharts Mixed Line and Bar, the JSON representation of the chart is: (unrelated fields omitted)

{
  "legend": { "data": ["Evaporation", "Precipitation", "Temperature"] },
  "xAxis": {
    "type": "category",
    "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
  },
  "yAxis": [
    {
      "type": "value",
      "name": "Precipitation",
      "min": 0,
      "max": 250,
      "interval": 50
    },
    {
      "type": "value",
      "name": "Temperature",
      "min": 0,
      "max": 25,
      "interval": 5
    }
  ],
  "series": [
    {
      "type": "bar",
      "name": "Evaporation",
      "data": [
        2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3
      ]
    },
    {
      "type": "bar",
      "name": "Precipitation",
      "data": [
        2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3
      ]
    },
    {
      "type": "line",
      "name": "Temperature",
      "data": [
        2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2
      ],
      "yAxisIndex": 1
    }
  ]
}

You can construct an Option in this way:

Legend legend = new Legend()
        .setData(new String[] { "Evaporation", "Precipitation", "Temperature" });

CategoryAxis xAxis = new CategoryAxis()
        .setType("category")
        .setData(new String[] { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" });

ValueAxis yAxis1 = new ValueAxis()
        .setType("value")
        .setName("Precipitation")
        .setMin(0)
        .setMax(250)
        .setInterval(50);

ValueAxis yAxis2 = new ValueAxis()
        .setType("value")
        .setName("Temperature")
        .setMin(0)
        .setMax(25)
        .setInterval(5);

BarSeries series1 = new BarSeries()
        .setName("Evaporation")
        .setType("bar")
        .setData(new Number[] { 2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3 });

BarSeries series2 = new BarSeries()
        .setName("Precipitation")
        .setType("bar")
        .setData(new Number[] { 2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3 });

LineSeries series3 = new LineSeries()
        .setName("Temperature")
        .setType("line")
        .setYAxisIndex(1)
        .setData(new Number[] { 2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2 });

Option option = new Option()
        .setLegend(legend)
        .setXAxis(xAxis)
        .setYAxis(new AxisOption[] { yAxis1, yAxis2 })
        .setSeries(new SeriesOption[] { series1, series2, series3 });

Engine provides methods to render the Option.

@jbaron
Copy link
Author

jbaron commented Apr 4, 2022

Thanks, looks like a nice solution and would indeed help!!!

Perhaps one more question I couldn't find the answer to (not sure where else to ask them). Can I somehow include Javascript functions, for example for custom tooltip functionality?

The only solution I could think of is something like this (likely some bugs in this code, just serves as an example):

server-side:

tooltip.setFormatter("function: function (params, ticket, callback) {...}")

client-side:

JSON.parse(optionStr, function (key, value) -> {
        if (typeof value == 'string' && value.startsWith("function:") {
             return Function('.....')
        } else {
             return value
        }
}

But perhaps I miss a feature?

@icepear-jzx
Copy link
Member

icepear-jzx commented Apr 5, 2022

ECharts Java doesn't support Javascript function as a formatter by far, though we have noticed that a formatter can be a callback function in Apache ECharts. Actually, we are looking for a solution for this. You solution is the most plausible way as far as I know.

In fact, the problem we are facing can be generalized to another common question: how to serialize a JS function into JSON?

There is a discussion about this: https://stackoverflow.com/questions/36517173/how-to-store-a-javascript-function-in-json

A solution mentioned there is similar to yours. However, some people also mentioned the security problems you may be concerned about.

Maybe ECharts Java will support JS functions and serialize them into {"function": {"arguments": string, "body": string}} in the future. And at the client side, you can call the Function() constructor.

However, I pessimistically think there is no perfect solution for this because writing JS code in Java code sounds really strange, and it probably violates programming principles.

By far, I think you have the following choices:

  1. Use string templates for simple usage.
  2. Serialize JS functions in backend and deserialize in frontend. We are willing to support this new feature if you really need it.
  3. Construct an Option in the client side (frontend). The backend server is only responsible for providing data. And we lose a user :(

@jbaron
Copy link
Author

jbaron commented Apr 5, 2022

Thanks for the elaborate answer. Right now the main reason why string templates typically don't suffice for our app is that there is no way to split the value parameter without using JavaScript. If there would be support for something a bit more flexible like this:

formatter: 'date: {c[0]} <br> value: {c[1]}'

I think we wouldn't require JavaScript functions. But of course that is an ECharts limitation, not your Java library.

Will experiment a bit more. Our current codebase is using plain Kotlin String manipulation to create the Option object and that is far worse ;) To see some of the charts we currently create and would like to migrate to the your Java library see: http://roboquant.org/screenshots.html

For serialisation and deserialisation of JavaScript code, we can already do that without explicit support in your library, so that is fine.

BTW, you can close this ticket if you like and thanks for the help so far!!!

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

No branches or pull requests

2 participants