【问题标题】:Select Visible Data选择可见数据
【发布时间】:2021-01-24 01:06:15
【问题描述】:

来自GitHub issue

我解决了这个获取可视化中显示的开始日期和结束日期的问题,然后我计算了这些日期之间的天数。根据之间的天数,我更改轴标签的时间格式。

这对我来说非常有用,因为我正在通过这个图表放大和缩小,当我放大时我需要知道有关日期的更多信息,当我缩小时我需要知道关于日期的信息较少。

我希望这对其他人有用。

如何做到这一点?具体来说,我不知道如何从交互式绘图中获取开始日期和结束日期。

【问题讨论】:

    标签: data-visualization vega-lite


    【解决方案1】:

    从 JupyterLab 执行此操作可能有点棘手,工作 around 一些 issues,但这里有几个单元格中的解决方案:

    首先是示例数据:

    import pandas as pd
    import numpy as np
    
    c1 = np.random.randint(1,6, size=15)
    c2 = pd.date_range(start="2021-01-01",end="2021-01-15")
    df = pd.DataFrame({"day": c2, "value": c1})
    df = df.drop([2, 5,6,7,13])
    df
    

    然后是 JupyterLab 的 Jinja,这样您就可以通过 Python 将 Vega-Lite 模式替换为 Vega-Embed。

    import jinja2
    import IPython
    import IPython.core.magic as ipymagic
    
    @ipymagic.magics_class
    class JinjaMagics(ipymagic.Magics):
    
        @ipymagic.cell_magic
        def jinja(self, line, cell):
            t = jinja2.Template(cell)
            r = t.render({k:v for k,v in self.shell.user_ns.items()
                                      if k not in self.shell.user_ns_hidden})
            d = getattr(IPython.display, line.strip(), IPython.display.display)
            return d(r)
    
    IPython.get_ipython().register_magics(JinjaMagics)
    

    然后是示例模式,稍微复杂一点来演示一些陷阱。

    import altair
    
    s =\
      { "mark": "bar"
      , "encoding":
        { "x":
          { "type": "temporal"
          , "bin": "binned"
          , "field": "start"
          , "axis":
            { "tickCount": "day"
              # For whatever reason a custom format function won't work
              # without a transform array.
            , "formatType": "interactiveFormatDate"
            , "format": "test"
            }
          }
        , "x2": {"field": "end"}
        , "y": {"type": "quantitative", "field": "value"}
        }
      , "selection":
        { "interactive":
          { "type": "interval"
          , "bind": "scales"
          , "encodings": ["x"]
          }
        }
      , "transform":
        [ # Convert 'day' from 'string' to timestamp ('number')
          {"calculate": "toDate(datum.day)", "as": "day"}
          # Provide "start" and "end" as Date objects to match the
          # type of temporal domain objects
        , {"calculate": "timeOffset('hours', datum.day, -12)", "as": "start"}
        , {"calculate": "timeOffset('hours', datum.day, 12)", "as": "end"}
        ]
      , "height": 250
      , "width": "container"
      , "$schema": "https://vega.github.io/schema/vega-lite/v4.json"
      , "config": {"customFormatTypes": "True"}
      }
    
    s["data"] = altair.utils.data.to_values(df)
    # While a data array can be named, transform array results can't.
    # Look at the Vega source to get the resulting name.
    s["data"]["name"] = "exp"
    s
    

    一些使用 Vega-Embed 的导入。

    # Tag Vega-Embed div's with UUIDs ensuring the correct div is targeted.
    import uuid
    import json
    

    最后,Vega-Embed。平心而论,我不确定这是获取脚本还是使用 JupyterLab 打包的脚本。

    %%jinja HTML
    {% set visid = uuid.uuid4() %}
    <html>
    <head>
        <style>.vega-embed.has-actions {width:90%}</style>
        <!-- Import Vega & Vega-Lite (does not have to be from CDN) -->
        <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
        <script src="https://cdn.jsdelivr.net/npm/vega-lite@4"></script>
        <!-- Import vega-embed -->
        <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
    </head>
    <body>
    
    <div id="vis-{{visid}}"></div>
    
    <script type="text/javascript">
        vega.expressionFunction('interactiveFormatDate', function(datum, params) {
            // Data points come from both the data fields backing the current channel, 
            // and from the axis domain. Temporal domain axis points are 'Date' objects
            // and are a subset of the visible domain. Data field points are always
            // included even when offscreen and are of whatever type provided to vega.
            var view = this.context.dataflow;
            // These are hacks because you have to inspect the generated vega to
            // determine the dataset names.
            var selection = view.data("interactive_store");
            var data = view.data("data_0");
            // Unless the view has been shifted the selection will be empty
            if (selection.length == 0){
                var d1 = data[0]["start"];
                var d2 = data[data.length-1]["start"];
            }
            else if (selection.length != 0){
                var d1 = selection[0]["values"][0][0];
                var d2 = selection[0]["values"][0][1];
            }
            var dd = (d2 - d1)/1000/60/60/24;
            var tf = vega.timeFormatLocale().timeFormat;
            var tl = ["%d %b", "%Y"];
            return tl.map(x => tf(x)(datum));
        });
        var spec = {{ json.dumps(s)}}
        vegaEmbed('#vis-{{visid}}', spec).then(function(result) {
            // Access the Vega view instance
            // (https://vega.github.io/vega/docs/api/view/) as result.view
        }).catch(console.error);
    </script>
    </body>
    </html>
    

    最烦人的方面是 HTML/JavaScript 单元格缺少正确的语法突出显示。

    【讨论】:

    • 只想说声谢谢!你的例子为我节省了几个小时!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 1970-01-01
    相关资源
    最近更新 更多