{"action":"created","issue":{"url":"https://api.github.com/repos/bokeh/bokeh/issues/3836","repository_url":"https://api.github.com/repos/bokeh/bokeh","labels_url":"https://api.github.com/repos/bokeh/bokeh/issues/3836/labels{/name}","comments_url":"https://api.github.com/repos/bokeh/bokeh/issues/3836/comments","events_url":"https://api.github.com/repos/bokeh/bokeh/issues/3836/events","html_url":"https://github.com/bokeh/bokeh/issues/3836","id":131877633,"number":3836,"title":"duck typing","user":{"login":"jonycgn","id":7364820,"avatar_url":"https://avatars.githubusercontent.com/u/7364820?v=3","gravatar_id":"","url":"https://api.github.com/users/jonycgn","html_url":"https://github.com/jonycgn","followers_url":"https://api.github.com/users/jonycgn/followers","following_url":"https://api.github.com/users/jonycgn/following{/other_user}","gists_url":"https://api.github.com/users/jonycgn/gists{/gist_id}","starred_url":"https://api.github.com/users/jonycgn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonycgn/subscriptions","organizations_url":"https://api.github.com/users/jonycgn/orgs","repos_url":"https://api.github.com/users/jonycgn/repos","events_url":"https://api.github.com/users/jonycgn/events{/privacy}","received_events_url":"https://api.github.com/users/jonycgn/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2016-02-06T17:22:34Z","updated_at":"2016-02-06T18:09:09Z","closed_at":null,"body":"hi,\r\n\r\ni have identified at least two instances in which bokeh doesn't behave like i would expect it to, given standard python practices. both come down to violations of the duck typing principle (which is one of the foundations python is built on), and they make my code a lot clumsier than necessary. also, because the error messages involved are not very helpful, it took me a long time to actually figure out what's going on.\r\n\r\nhere's the first instance. it shouldn't matter what type of container you pass, as long as it behaves as it is expected to. simple example:\r\n\r\n    import numpy\r\n    from bokeh.plotting import figure, show\r\n    t = numpy.arange(10)\r\n    x = numpy.linspace(1, 2, 10)\r\n    p = figure()\r\n    p.multi_line([t], [x])\r\n    show(p)\r\n\r\nif i replace `p.multi_line([t], [x])` with `p.multi_line(numpy.array([t]), numpy.array([x]))`, i get the following error:\r\n\r\n    /users-local/balle/anaconda/envs/2016-02-03/lib/python2.7/site-packages/bokeh/plotting_helpers.pyc in _process_sequence_literals(glyphclass, kwargs, source)\r\n        134 \r\n        135         if isinstance(val, np.ndarray) and val.ndim != 1:\r\n    --> 136             raise RuntimeError(\"Columns need to be 1D (%s is not)\" % var)\r\n        137 \r\n        138         source.add(val, name=var)\r\n\r\n    RuntimeError: Columns need to be 1D (xs is not)\r\n\r\nnot only do i not understand what this error message is trying to tell me, it is also nonsensical in that all i did was exchange one iterable type (builtin list) by another one (numpy array). this shouldn't be an error at all, given that iterating a 2d numpy array behaves exactly the same way as iterating a list of 1d numpy arrays. so, if i already have 2d numpy arrays ts and xs which contain all of the data, i actually have to explicitly construct a list in order to make this example work:\r\n\r\n    p.multi_line([t for t in ts], [x for x in xs])\r\n\r\nthis isn't very \"pythonic\" and makes the code less readable.\r\n\r\nthe second instance i ran into is about scalar types, and in a way it is even more fundamental. example:\r\n\r\n    import numpy\r\n    from bokeh.charts import Line, show\r\n    data = {\r\n        't': numpy.arange(10),\r\n        0: numpy.linspace(1, 2, 10),\r\n        1: numpy.linspace(2, 3, 10),\r\n    }\r\n    p = Line(data, x = 't', y = range(2))\r\n    show(p)\r\n\r\nhere, if i construct the two data columns instead as\r\n\r\n    data = {\r\n        't': numpy.arange(10),\r\n        0: numpy.linspace(1, 2, 10).astype(numpy.float32),\r\n        1: numpy.linspace(2, 3, 10).astype(numpy.float32),\r\n    }\r\n\r\ni get the following error:\r\n\r\n    /users-local/balle/anaconda/envs/2016-02-03/lib/python2.7/site-packages/bokeh/properties.pyc in __set__(self, obj, value)\r\n        210                     break\r\n        211             else:\r\n    --> 212                 raise e\r\n        213         else:\r\n        214             value = self.transform(value)\r\n\r\n    ValueError: expected an element of either String, Column(Float), Column(String), Column(Datetime) or Column(Bool), got 0    1.000000\r\n    1    1.111111\r\n    2    1.222222\r\n    3    1.333333\r\n    4    1.444444\r\n    5    1.555556\r\n    6    1.666667\r\n    7    1.777778\r\n    8    1.888889\r\n    9    2.000000\r\n    Name: value, dtype: float32\r\n\r\nagain, this error message really isn't very helpful in understanding what the problem is, and i only figured out that accidentally passing a different floating point type is the issue by extensive experimentation. what's more important, i believe this shouldn't be an error at all.\r\n\r\npython code should not rely on explicit type checking wherever possible. this makes the code more portable, cleaner, and enables many of the nice things you can do with python.\r\n\r\nsince i haven't been trying out bokeh for a long time, it is possible that i'm missing a really good reason why it should behave in this way, but honestly i can't think of one. if that's the case, please tell me.\r\n"},"comment":{"url":"https://api.github.com/repos/bokeh/bokeh/issues/comments/180825333","html_url":"https://github.com/bokeh/bokeh/issues/3836#issuecomment-180825333","issue_url":"https://api.github.com/repos/bokeh/bokeh/issues/3836","id":180825333,"user":{"login":"jonycgn","id":7364820,"avatar_url":"https://avatars.githubusercontent.com/u/7364820?v=3","gravatar_id":"","url":"https://api.github.com/users/jonycgn","html_url":"https://github.com/jonycgn","followers_url":"https://api.github.com/users/jonycgn/followers","following_url":"https://api.github.com/users/jonycgn/following{/other_user}","gists_url":"https://api.github.com/users/jonycgn/gists{/gist_id}","starred_url":"https://api.github.com/users/jonycgn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jonycgn/subscriptions","organizations_url":"https://api.github.com/users/jonycgn/orgs","repos_url":"https://api.github.com/users/jonycgn/repos","events_url":"https://api.github.com/users/jonycgn/events{/privacy}","received_events_url":"https://api.github.com/users/jonycgn/received_events","type":"User","site_admin":false},"created_at":"2016-02-06T18:09:09Z","updated_at":"2016-02-06T18:09:09Z","body":"as an additional explanation, i was initally thrown off by the convention of calling an array of data a \"column\". i can see now that this originates from spreadsheets, where data is typically arranged in columns.\r\n\r\ni have no experience with pandas, but quite a bit of experience with numpy arrays/tensors. so in the first example, if you represent all data as an \"iterable of iterables\", i.e., a 2d data structure/matrix, the 1d data \"columns\" are really in the rows of that matrix. this is why the first error message was quite confusing to me."}}